Одиничні тести: відкладені твердження з Linq


18

Чи нормально додавати такі відкладені твердження

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

Чому? Тож я можу повторити лише один раз навіть із заявами, що очікують матеріалізованої колекції, наприклад:

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

А також це може бути не просто Select, а метод з визначеним ітератором, що має багато перевірок та логіки (наприклад, деякий підрахунок та фільтрація).

Суть сумніву полягає у складності читання та налагодження такого коду у разі невдачі тесту.


1
Я б не покладався на це для тестування, але іноді добре це робити у виробничому коді, якщо немає кращого рішення. Ви можете зробити собі допоміжну функцію, sequence.WithSideEffect(item => Assert.IsCute(item))щоб зробити її більш чистою.
usr

@usr Схоже, ви схопили головний недолік такого способу - Побічний ефект від ітератора.
СерГ

Чи вам ще не потрібно повторювати двічі, один раз для створення списку і знову для порівняння 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()); 

    }

Це означає, що перший тест насправді марний, оскільки він не допомагає знайти помилку. Ви не знаєте, чи не вдалось, оскільки номер недійсний або тому, що обидві колекції були різними.


Чому? Тож я можу повторити лише один раз навіть із заявами, що очікують матеріалізованого збору

Цікаво, чому ти дбаєш про це? Це одиничні тести. Вам не доведеться оптимізувати кожен їх шматочок, і зазвичай тести не вимагають мільйонів предметів, тому продуктивність не повинна викликати занепокоєння.

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


Якщо з якоїсь причини твердження потрібно поховати в контрольному потоці, одним із способів переконатися, що воно було виконане, є збереження лічильника / прапора, який збільшується / встановлюється на істину перед вкладеним твердженням. Пізніше ми можемо стверджувати, що очікуваний контрольний потік був прийнятий, перевіривши цей лічильник. Не ідеально, але багато в чому стосується вашої першої критики.
амон

1
Крім того, ви або хтось інший повернетесь до відкладеного твердження через 6 місяців і вам доведеться витрачати час на його з'ясування.
DavidTheWin

У вашому прикладі щось не так. Виклик ToListповторить численні, чи не так?
RubberDuck

1
@RubberDuck так, воно буде, і воно також вийде з ладу, але не на рівні, Assert.Failа на, CollectionAssertі ви не зможете сказати, яке твердження насправді пішло не так. Я маю на увазі, що VS не зосередиться на Assert.Failіншому, але зараз ви можете налагоджувати.
t3chb0t
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.