Всякий раз, когда я пишу модульные тесты, я всегда старался иметь по одному утверждению на тест, чтобы облегчить отладку при сбое тестов. Однако, следуя этому правилу, я чувствую, что постоянно копирую один и тот же код в каждом тесте, и, имея больше тестов, становится труднее вернуться к чтению и сопровождению.
Так что тестирование с одним утверждением нарушает DRY?
И есть ли хорошее правило, которому нужно следовать, чтобы найти хороший баланс, как, например, проведение одного теста на метод ? *
* Я понимаю, что, вероятно, не существует универсального решения для этого, но есть ли рекомендуемый способ подойти к этому?
testing
unit-testing
dry
Корей Хинтон
источник
источник
Ответы:
Правильные модульные тесты имеют соглашение об именах, которое помогает вам сразу определить, что не удалось:
Вот почему у вас есть одно утверждение на тест, так что каждый метод (и его имя) соответствует условию, которое вы утверждаете.
Как вы правильно указали, каждый новый тест будет иметь похожий код установки. Как и в случае с любым другим кодом, вы можете преобразовать общий код в собственный метод, чтобы уменьшить или устранить дублирование и сделать ваш код более СУХИМЫМ. Некоторые среды тестирования специально разработаны для того, чтобы вы могли разместить этот установочный код в одном месте .
В TDD ни один тест не является YAGNI, потому что вы пишете тесты, основываясь только на том, что требуется от вашего кода. Если вам это не нужно, вы не будете писать тест.
источник
Нет, но это способствует нарушению.
Тем не менее, хороший объектно-ориентированный дизайн имеет тенденцию выходить за рамки для модульных тестов - в основном по уважительной причине. Более важно, чтобы модульные тесты были изолированы друг от друга, чтобы тест можно было опросить изолированно и, если необходимо, зафиксировать с уверенностью, что вы не нарушите другие тесты. По сути, правильность и читаемость теста важнее его размера или удобства обслуживания.
Честно говоря, я никогда не был поклонником правила «одно утверждение для каждого теста» по причинам, которые вы описываете: это приводит к большому количеству шаблонного кода, который трудно читать, легко неправильно разбирать и трудно исправить, если вы будете проводить рефакторинг (что заставляет вас меньше заниматься рефакторингом).
Если функция должна возвращать список «foo» и «bar» для заданного ввода, но в любом порядке, вполне нормально использовать два утверждения, чтобы проверить, что оба они находятся в наборе результатов. Когда вы сталкиваетесь с проблемами, когда один тест проверяет два входа или два побочных эффекта, и вы не знаете, какой из двух вызвал сбой.
Я рассматриваю это как вариант Принципа единой ответственности: должно быть только одно, что может привести к провалу теста, и в идеальном мире это изменение должно нарушить только один тест.
Но в конце концов это компромисс. Вы с большей вероятностью потратите больше времени на поддержание всего копируемого кода, или же вы потратите больше времени на поиск первопричин, когда тесты могут быть нарушены несколькими источниками. Пока вы пишете "некоторые" тесты, это, вероятно, не имеет большого значения. Несмотря на мое пренебрежение к тестам с одним утверждением, я склонен ошибаться в сторону большего количества тестов. Ваш пробег может варьироваться.
источник
Нет. Это похоже на то, как ты это делаешь. Если вы не нашли заметную ссылку, где они утверждают, что это хорошая практика.
Используйте тестовое приспособление (хотя в терминологии XUnit набор тестов, установка и разборка - это фиксатор), то есть некоторые настройки или примеры, применимые ко всем вашим тестам.
Используйте методы, которые вы обычно используете для структурирования своего кода. Когда рефакторинг тесты обычный TDD Red-Green-Refactor не применяются, вместо них будут применяться, «Рефакторинг в красном». Это,
Таким образом, вы знаете, что тесты все еще дают положительные и отрицательные результаты.
Существует несколько стандартных форматов для тестов. Например, Arrange, Act, Assert или Given When, Then (BDD) . Рассмотрите возможность использования отдельной функции для каждого шага. Вы должны быть в состоянии вызвать функцию, чтобы уменьшить шаблон.
источник