Почему должен быть только один Assert?


5 0

Недавно смотрел видео, в котором специалист из MS рассказывал про юнит тесты, кажется я его смотрел на Channel 9. Так там затронули тему того, что рекомендуется, чтобы у каждого теста был только один Assert. Один тест - одна проверка. 

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

Лично я не против большого количества проверок Assert и не понимаю, зачем их ограничивать. Вот сейчас я пишу тесты для системы, которая будет давать какие-то перки за определенные действия - клиент называет это Promotion Engine. Там клиент конфигурирует различные промоушены, потом загружаются данные, и движок на основе данных проверяет, должен ли я дать призы тем, кто хорошо играет в игры или нет. 

У меня тесты налету создают разные конфигурации промоушенов, вставляют данные, потом ассерты проверяют, что данные существуют в системе и они корректно созданы. Потом прогоняется Promotion Engine и снова несколько Assert-ов проверяют результат, чтобы все было в порядке. Потом могут добавляться новые данные, снова можно прогнать движок и снова проверить, что результат изменился. И таким образом я проверяю каждый этап, каждый шаг, каждое изменение данных во времени. 

Есть и более простые тесты, которые проверяют только небольшие участки кода, но много и таких больших, которые проверяют весь процесс. 

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

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

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

Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Kastor

13 Июля 2017

Asserts может быть несколько, но они должны тестировать один сценарий.
Главное правило такое - упал один тест - у нас одна проблема. Упало два теста - две проблемы.

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

А еще мне показалось, что у тебя одни тесты зависят от других. Так ли это?


he

13 Июля 2017

Как я делаю : ставлю столка ассерт штоби легко можна понят где ошибка. Если из теста трудно понят где ошибка, тест нада изменит


Михаил Фленов

13 Июля 2017

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

На примере уже упомянутого мной промоушн движка, как я тестирую простой success path:

1. Создать транзакцию
2. Truncate table с действиями пользователя
3. Создать объявление промоушена
4. Прогнать промоушн
5. Assert на результирующие данные, чтобы убедится, что никто не получил призов, ведь действий пользователя нет
6. Добавить действия
7. Прогнать промоушн и убедится, что приз получен
8. Прогнать промоушн и убедится, что нет дубликата

Кто-то может сказать, что я тестирую три разве вещи:
1. Никто не получает при отсутствии данных
2. Реальный success path
3. Тест на дубликат

Но если их разделить на три, я же не упрощу себе жизнь. Если ошибка будет в первом, то рухнут все три и мне от этого проще искать реальную проблему не будет

Ну в конце у меня конечно же rollback и ничего в базе не остаётся.


Overdrive

13 Июля 2017

2Михаил Фленов
Так это уже интеграционный тест. Юнит тест когда проверяется только один модуль и только его функциональность и зависимые объекты поменяются моками в DI контейнере. А так ты получается тестируешь всю цепочку бизнес-логики. Если у приложения плохой дизайн, обычно проблематично написать юнит тесты, и в основном пишутся одни интеграционные.


Михаил Фленов

13 Июля 2017

Я не заметил цепочки. Есть один модуль с одним классом, который называют крутым словом engine, но он простой - запрос на получение людей, которые сделали какое-то действие. Да, у меня есть подготовительные вещи, типа создания определения, но я даже не проверяю, правильно ли создана конфигурация. Я прогоняю один и тот же метод Process в одном и том же классе, который назвали XXXXPromotion несколько раз и смотрю результат в одном и том же тесте. Там есть и другие XXXXPromotion классы с таким же Process методом, которые делают примерно подобные вещи. Но факт остается фактом, что я тестирую один метод.

Можно создать несколько тестов, каждый из которых будет прогонять метод Process по одному разу (хотя тест на дубликаты все же вынужден будет выполнять дважды), а можно обойтись одним тестов.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне