У меня есть (enum: int) AccessOptions, который используется для заполнения словаря, чтобы отразить простые свойства доступа для индексированного списка основных имен пользователей.
Мне нужно было поддерживать модульное тестирование, в частности
Assert.AreEqual
<Dictionary<string, AccessOptions>,
Dictionary<string, AccessOptions>)
... который запутан и вызывает общий оператор равенства Dictionary, который на самом деле проверяет только ссылочные значения - мне нужно установить, что два разных ссылочных объекта содержат одни и те же ключи по значению, и что связанные значения этих ключей совпадают в каждом кейс.
Итак, я написал свой собственный оператор равенства и создал класс, который расширяет Dictionary, чтобы не испортить объекты Dictionary в моем проекте. Когда этот метод выполняется в Visual Studio 2016 в контексте отладки вызова Assert.AreEqual юнит-теста, несколько вещей идут не так, и я отмечу их ниже с помощью комментариев.
public class SecretAccessRuleSet : Dictionary<string, AccessOptions>
{
public SecretAccessRuleSet() {}
public SecretAccessRuleSet(int size) : base (size) {}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((SecretAccessRuleSet) obj);
}
public static bool operator == (SecretAccessRuleSet a, SecretAccessRuleSet b)
{
if (ReferenceEquals(a, b))
{
return true;
}
/* When the below statement executes in debug, I can watch
* execution flow from the equality test against (object)a,
* straight to "return false" -- but execution does not actually
* return, but appears to jump directly to the foreach statement
* two blocks down. It might be important, or just a bug.
*/
if (((object)a == null) || ((object)b == null))
{
return false;
}
if (a.Count != b.Count)
{
return false;
}
/* Then when we get here, the visualizer highlights a; I advance
* one line and it highlights "in", which I assume is wherein an
* enumerator is initialized; I advance again and we jump to the
* end of the method! Literally to the end curly brace.
*/
foreach (var entry in a)
{
AccessOptions bOpt;
if (!b.TryGetValue(entry.Key, out bOpt)
|| bOpt != entry.Value)
{
return false;
}
}
// If we get here, they're equal
return true;
}
public bool Equals(SecretAccessRuleSet other)
{
return this == other;
}
public static bool operator !=(SecretAccessRuleSet a, SecretAccessRuleSet b)
{
return !(a == b);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
Результаты теста показывают, что вызов Assert.AreEqual(a, b) вернул false, но я очень мало верю в то, что содержимое любой коллекции было оценено, и я не понимаю, почему.
Я, вероятно, удалю все это и создам отдельный способ тестирования без переопределения оператора, но что здесь пошло не так?
(Спасибо всем, за ваше время.)
Обновление: чтобы указать то, что я забыл, обе коллекции имеют ожидаемый тип, ненулевой, и обе содержат 2 записи — на самом деле одни и те же 2 записи; Я ожидал, что оператор равенства вернет true в тесте.
Обновление 2: я отделил нулевые проверки; "(object) a == null" оценивается как false и продолжается, но "(object) b == null" оценивается как true и отправляет выполнение на "return false" - но опять же, те же две проблемы, когда выполнение на самом деле не возвращает, но пытается перечислить первое... и b на самом деле не равно нулю. Есть ли причины, по которым b будет допустимым объектом, но операция приведения в (объект) b может завершиться неудачей?
a
и просмотреть содержимое. Если он пустой, это ваша проблема. - person nhouser9   schedule 11.08.2016!=
дляAccessOptions
? - person recursive   schedule 11.08.2016CollectionAssert.AreEqual
? msdn.microsoft.com/en-us/library/ms243763.aspx - person Eris   schedule 11.08.2016