Придерживается ли в этом случае одно утверждение на тест глупой последовательности?

10

У меня есть класс, который я тестирую. У класса есть функция:apply(List<IRule> rules, List<ITarget> targets);

В одном тесте я хочу убедиться, что каждая цель была передана одному правилу, а именно:

rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));

Мне кажется, что ограничиться одним утверждением было бы просто хобгоблином . Я прав в этом предположении, или есть какой-то другой способ, которым я мог бы утверждать, что каждая цель, на самом деле, была проверена?

Уэйн Вернер
источник
Я вижу фьорды!
Росс Паттерсон

Ответы:

15

Три утверждения по сути являются одним тестом. Вы тестируете поведение метода в коллекции, чтобы убедиться, что каждый элемент был параметром для определенного вызова (т. Е. Что каждый элемент был обработан должным образом).

Установка данных три раза и тремя различными способами является расточительной и менее читаемой, чем альтернатива, состоящая из нескольких утверждений.

«Правило» единственного утверждения больше относится к созданию утверждений разных типов в одних и тех же методах (по сути, для проверки разных вещей), что в действительности не применимо в этом случае, когда вы проверяете одно поведение.

Одед
источник
3
В самом деле: правило - это более одного логического утверждения на модульный тест. Вы можете сгруппировать их в один более высокий уровень, утверждая, что вы можете использовать их в разных тестах.
Лоран Бурго-Рой
5

Я считаю, что это одно утверждение для каждого теста, чтобы ваши тесты были сосредоточены на одной проблеме. Если вы тестируете 20 вещей за один тест, очень сложно сказать, каков ваш охват. Вы знаете, что это вызывает проблему, когда вы не можете назвать метод теста без слова и в нем. Например, если ваш метод теста будет более точно назван как testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur(), вы, вероятно, слишком много тестируете в одном тесте.

В вашем случае, я думаю, что это нормально утверждать три раза. Если вы хотите сделать ваш код более читабельным, вы можете извлечь эти три утверждения в метод с именем assertWasCalledOnTargets(...).

Даниэль Каплан
источник
3

Для вашего конкретного примера вы можете использовать «один» оператор assert, если вы делаете что-то вроде:

foreach target in targets
{
     rule1.AssertWasCalled(fnord => fnord.Test(target))
}

Это то, что я делаю, чтобы избежать чувства вины за то, что в одном тесте было несколько утверждений.

Джефф Б
источник
Я делал это раньше. Не плохой путь. Его легко читать, и вы можете понять природу того, что он делает.
CokoBWare
1

Я тоже боролся с этим.

Пурист (во мне) настаивает на одном утверждении за тест, так что я точно буду знать , где все взорвалось.

А потом я обнаружил, что копирую / вставляю много одного и того же избыточного кода для настройки теста. После третьего или четвертого слоя вы начинаете говорить "Ой! Хватит!"

Мой компромисс состоял в том, чтобы найти аспекты, которые «никогда» не ломаются. И я сложу эти кусочки вместе, а затем добавлю один новый элемент, который может сломаться. Просто для ясности, наложение нескольких изменчивых областей в одном тесте было бы нарушением этого компромисса.


источник
1
Вы должны проверить Assume. Я только что узнал об этом сегодня.
Уэйн Вернер
1

Если код настройки для target1отличается от кода настройки для target2, этот тип обрезки углов в конечном итоге приводит к чрезмерно длинному коду инициализации теста. Это, в свою очередь, либо беспорядок, либо заканчивается рефакторингом и повторным использованием. Если ваши тесты достаточно сложны, чтобы оправдать их рефакторинг, ваш тест, вероятно, проверяет более чем одну вещь.

Если код настройки для каждой цели по сути одинаков, разделение теста на несколько отдельных тестов, вероятно, является излишним.

Если target1и target2являются разными реализациями одного и того же интерфейса, вы должны вместо этого добавить модульный тест в интерфейс (и позволить вашей тестовой среде генерировать тест для каждой реализации этого интерфейса).

Брайан
источник