Можно ли копировать и вставлять юнит-тесты, когда логика в основном одинакова? - PullRequest
20 голосов
/ 08 августа 2010

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

Разве это плохо, если я просто скопирую 10 тестов, которые у меня уже есть, для левого движения и сделаю только необходимые изменения и сделаю то же самое длясам код тоже?Или я должен пойти снова и сделать каждый тест с самого начала, даже если логика в основном одинакова?

Ответы [ 9 ]

30 голосов
/ 08 августа 2010

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

Суть в том, что дублирование кода - почти всегда неправильная вещь. В этом примере вы можете преобразовать код проверки в вызываемый метод, например IsTetrisPieceUnableToMoveLeftBecauseOfAPieceOrAWall. Я всегда использую очень описательные имена методов, подобные этим, когда пишу немного «разделяемой» функциональности для модульного теста, так как он делает чрезвычайно ясным только то, что делается / тестируется.

26 голосов
/ 09 августа 2010

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

  • Производственный код может предоставить некоторую сложность, чтобы быть понятным / поддерживаемым.Вы хотите, чтобы код был на правильном уровне абстракции, а дизайн был согласованным.Это нормально, потому что у вас есть тесты и вы можете убедиться, что он работает.Дублирование кода в рабочем коде не было бы проблемой, если бы у вас действительно было 100% покрытие кода на логическом уровне.Этого действительно трудно достичь, поэтому правило таково: избегайте дублирования и максимизируйте охват кода.

  • С другой стороны, тестовый код должен быть максимально простым.Вы должны убедиться, что тестовый код действительно проверяет, что он должен.Если тесты сложные, вы можете столкнуться с ошибкой в ​​тестах или неправильными тестами - и у вас нет тестов для тестов, поэтому правило таково: держите это простым.Если тестовый код дублируется, это не такая большая проблема, когда что-то меняется.Если изменение применяется только в одном тесте, в другом произойдет сбой, пока вы его не исправите.

Главное, что я хочу подчеркнуть, - это то, что рабочий и тестовый коды имеют различную природу.Тогда это всегда вопрос здравого смысла, и я не говорю, что вы не должны анализировать тестовый код и т. Д. Если вы можете что-то учитывать в тестовом коде и уверены, что все в порядке, то сделайте это.Но для тестового кода я бы предпочел простоту, а не элегантность, а для производственного кода я бы предпочел элегантность, а не простоту.Оптимально, конечно, иметь простое, элегантное решение:)

PS: Если вы действительно не согласны, пожалуйста, оставьте комментарий.

14 голосов
/ 08 августа 2010

Тестовый код, как и любой другой код, должен поддерживаться и подвергаться рефакторингу.

Это означает, что если у вас есть общая логика, извлеките ее в свою собственную функцию.

Некоторые библиотеки модульных тестовпоскольку семейство xUnit имеет специальные атрибуты тестового устройства, настройки и завершения для такого общего кода.

См. этот связанный вопрос - «Почему копирование кода вставки кода опасно?».

8 голосов
/ 08 августа 2010

Нет ничего плохого в копировании, и это хорошее место для начала.Действительно, это лучше, чем с нуля, так как если у вас есть рабочий код (будь то тесты или иным образом), то копирование-вставка будет более надежной, чем с нуля, а также быстрее.

Однако это только шаг1. Шаг 2 - рефакторинг для общности, а шаг 1 - только для того, чтобы помочь вам увидеть эту общность.Если вы уже ясно видите это без копирования (иногда проще сначала скопировать, а потом проверить, иногда нет, и это зависит от того, кто это делает), пропустите шаг 1.

1 голос
/ 10 августа 2010

Я согласился @Rob.Код нуждается в рефакторинге.Но если вы не хотите проводить рефакторинг кода в данный момент, тогда вы можете пойти и провести параметризованные тесты.Один и тот же тестовый прогон для разных параметров.См. TestCase и TestCaseSource атрибуты в nunit.

См. http://nunit.org/index.php?p=parameterizedTests&r=2.5

1 голос
/ 09 августа 2010

Веб-сайт xunitpatterns.org говорит «нет» (копировать / вставить не в порядке), поскольку это может увеличить затраты, когда необходимо обновить тесты:

"Cut and Paste" - мощный инструмент для быстрого написания кода, но он приводит к множеству копий одного и того же кода, каждый из которых должен быть поддерживается параллельно.

и для дальнейшего чтения также ссылки на статью

Автор: Эри ван Дёрсен, Леон Мунен, Алекс ван ден Берг, Джерард Кок

1 голос
/ 09 августа 2010

Помните, что ваши тесты давят на ваш код.если вы обнаружите, что ваши тесты выглядят дублированными, за исключением чего-то вроде left / right, то, возможно, есть некоторый базовый код, который left и right дублирует.Так что вы можете посмотреть, сможете ли вы реорганизовать свой код, чтобы использовать его влево или вправо и отправить ему левый или правый флаг.

1 голос
/ 09 августа 2010

Если вы повторяете код, то вы должны провести рефакторинг. Ваша ситуация является распространенной проблемой и решается с помощью «Параметрического тестирования». Параметрическое тестирование, когда поддерживается тестовым жгутом, позволяет передавать несколько наборов входных значений в качестве параметров. Вы также можете посмотреть Fuzz-тестирование. Я обнаружил, что оно полезно в таких ситуациях.

0 голосов
/ 24 мая 2018

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

С другой стороны, если ваш модульный тест имеет +100500 строк кода, то он, очевидно, должен быть реорганизован, и это будет упрощением.

И, конечно же, старайтесь избегать бессмысленного дублирования модульных тестов, например, тестирование 1 + 1 = 2, 2 + 2 = 4, 3 + 3 = 6 Напишите основанные на данных тесты, если вам действительно нужно тестировать один и тот же метод на разных данных.

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