Как Assert.AreEqual определяет равенство между двумя универсальными IEnumerables?

StackOverflow https://stackoverflow.com/questions/933285

Вопрос

У меня есть модульный тест, чтобы проверить, возвращает ли метод правильный IEnumerable.Метод создает перечисляемое, используя yield return.Класс, перечислимым которым он является, приведен ниже:

enum TokenType
{
    NUMBER,
    COMMAND,
    ARITHMETIC,
}

internal class Token
{
    public TokenType type { get; set; }
    public string text { get; set; }
    public static bool operator == (Token lh, Token rh) { return (lh.type == rh.type) && (lh.text == rh.text); }
    public static bool operator != (Token lh, Token rh) { return !(lh == rh); }
    public override int GetHashCode()
    {
        return text.GetHashCode() % type.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return this == (Token)obj;
    }
}

Это соответствующая часть метода:

 foreach (var lookup in REGEX_MAPPING)
 {
     if (lookup.re.IsMatch(s))
     {
         yield return new Token { type = lookup.type, text = s };
         break;
     }
 }

Если я сохраню результат этого метода в actual, создайте еще одно перечислимое expected, и сравните их вот так...

  Assert.AreEqual(expected, actual);

..., утверждение неверно.

Я написал метод расширения для IEnumerable это похоже на Python zip функция (он объединяет два IEnumerables в набор пар) и попробовал следующее:

foreach(Token[] t in expected.zip(actual))
{
    Assert.AreEqual(t[0], t[1]);
}

Это сработало!Так в чем же разница между этими двумя Assert.AreEqualс?

Это было полезно?

Решение

Assert.AreEqual собирается сравнить два имеющихся объекта. IEnumerables сами по себе являются типами и предоставляют механизм для перебора некоторой коллекции... но на самом деле они не являются этой коллекцией.В исходном сравнении сравнивались два IEnumerables, это корректное сравнение... но не то, что вам нужно.Вам нужно было сравнить что за двое IEnumerables были предназначены для перечисления.

Вот как я сравниваю два перечислимых числа:

Assert.AreEqual(t1.Count(), t2.Count());

IEnumerator<Token> e1 = t1.GetEnumerator();
IEnumerator<Token> e2 = t2.GetEnumerator();

while (e1.MoveNext() && e2.MoveNext())
{
    Assert.AreEqual(e1.Current, e2.Current);
}

Я не уверен, что приведенное выше кода меньше, чем ваш .Zip метод, но он настолько прост, насколько это возможно.

Другие советы

Нашел:

Assert.IsTrue(expected.SequenceEqual(actual));

Рассматривали ли вы возможность использования CollectionAssert вместо этого класс... учитывая, что он предназначен для проверки равенства коллекций?

Приложение:
Если сравниваемые «коллекции» являются перечислениями, то просто оберните их с помощью 'new List<T>(enumeration)' - это самый простой способ выполнить сравнение.Конечно, создание нового списка вызывает некоторые накладные расходы, но в контексте модульного теста это не должно иметь большого значения, я надеюсь?

Я думаю, что самый простой и понятный способ добиться желаемого равенства — это комбинация ответа jerryjvl и комментария к его сообщению MEMark — объединить CollectionAssert.AreEqual с методами расширения:

CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());

Это дает более подробную информацию об ошибках, чем ответ SequenceEqual, предложенный OP (он сообщит вам, какой элемент был найден неожиданным).Например:

IEnumerable<string> expected = new List<string> { "a", "b" };
IEnumerable<string> actual   = new List<string> { "a", "c" }; // mismatching second element

CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray());
// Helpful failure message!
//  CollectionAssert.AreEqual failed. (Element at index 1 do not match.)    

Assert.IsTrue(expected.SequenceEqual(actual));
// Mediocre failure message:
//  Assert.IsTrue failed.   

Ты будешь Действительно рад, что вы сделали это таким образом, если/когда ваш тест терпит неудачу - иногда вы даже можете узнать, что не так, без необходимости запускать отладчик - и эй, вы правильно делаете TDD, поэтому вы сначала пишете неудачный тест, верно?;-)

Сообщения об ошибках становятся еще более полезными, если вы используете AreEquivalent для проверки эквивалентности (порядок не имеет значения):

CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList());
// really helpful error message!
//  CollectionAssert.AreEquivalent failed. The expected collection contains 1
//  occurrence(s) of <b>. The actual collection contains 0 occurrence(s).   
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top