Модульные тесты: отложенные утверждения с Linq

18

Это нормально, чтобы добавить отложенные утверждения, как это

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

Почему? Так что я могу выполнить итерацию только один раз, даже если операторы ожидают материализованную коллекцию, например:

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

А также это может быть не просто Select, но метод с определенным итератором, имеющий много проверок и логику (например, некоторые подсчеты и фильтрации).

Семя сомнений заключается в сложности чтения и отладки такого кода в случае неудачного тестирования.

SerG
источник
1
Я бы не стал полагаться на это при тестировании, но иногда это нормально делать в рабочем коде, если нет лучшего решения. Вы можете сделать себе вспомогательную функцию, sequence.WithSideEffect(item => Assert.IsCute(item))чтобы сделать его чище.
USR
@usr Похоже, вы поймали ключевой недостаток такого способа - побочный эффект от итератора.
SerG
Разве вам не нужно повторять дважды, один раз, чтобы сгенерировать список, и снова сравнить его с expectedKittens? Вы только что скрыли итерации за вызовами методов.
IllusiveBrian
@IllusiveBrian В этом смысле, в примере, да. Это все еще меньше, чем с дополнительным .All().
SerG

Ответы:

37

Можно ли добавить отложенные утверждения, подобные этому [..]

Нет , это не так. Почему? Потому что, если вы по какой-либо причине удалите второе утверждение, тест все равно станет зеленым, и вы подумаете, что он все еще работает, но это не так, поскольку коллекция не будет перечислена. Если у вас есть два или более независимых утверждения, они будут продолжать выполнять свою работу, даже если вы отключите одно из них.

Рассмотрим эту комбинацию:

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

Теперь, даже если вы отключите или удалите одно из утверждений, другое все равно выполнит свою работу. Также, если вы забудете материализовать коллекцию, ее запуск может занять больше времени, но она все равно будет работать. Независимые тесты являются более надежными и надежными.

Существует также второй нет . Я не уверен, как другие фреймворки справляются с этим, но если вы используете платформу MS Test, вы не узнаете, какой тест не удался. Если вы дважды щелкнете по неудачному тесту, он покажет вам, CollectionAssertкак неудачный, но на самом деле это была вложенная Assertошибка, и отладка будет чрезвычайно сложной. Вот пример:

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

Это означает, что первый тест на самом деле бесполезен, потому что он не помогает найти ошибку. Вы не знаете, произошел ли сбой, потому что число было недействительным или потому что обе коллекции были разными.


Почему? Так что я могу повторить только один раз, даже если операторы ожидают материализованную коллекцию

Интересно, почему вы заботитесь об этом? Это юнит-тесты. Вам не нужно оптимизировать каждый их бит, и обычно тесты не требуют миллионов элементов, поэтому производительность не должна быть проблемой.

Вам нужно будет поддерживать такие тесты, так почему вы должны сделать их более сложными, чем необходимо? Напишите простые утверждения, которые работают.

t3chb0t
источник
Если по какой-то причине утверждение действительно необходимо скрыть в потоке управления, один из способов убедиться, что оно выполнено, - сохранить счетчик / флаг, который увеличивается / устанавливается в значение true перед вложенным утверждением. Позже мы можем утверждать, что ожидаемый поток управления был взят путем проверки этого счетчика. Не идеально, но в основном относится к вашей первой критике.
Амон
1
Кроме того, вы или кто-то еще вернетесь к отложенному утверждению через 6 месяцев и потратите время на его выяснение.
DavidTheWin
Что-то не так с вашим примером. Вызов ToListбудет повторять перечисляемый, не так ли?
RubberDuck
1
@RubberDuck да, это будет, и это также потерпит неудачу, но не в, Assert.Failа в, CollectionAssertи вы не сможете сказать, какое утверждение на самом деле пошло не так. Я имею в виду, что VS не будет фокусироваться, Assert.Failа на другом ... теперь вы можете отлаживать.
t3chb0t