Я считаю, что это заблуждение, как я могу думать.
Тестовый код, который тестирует производственный код, совсем не похож. Я продемонстрирую в Python:
def multiply(a, b):
"""Multiply ``a`` by ``b``"""
return a*b
Тогда простой тест будет:
def test_multiply():
assert multiply(4, 5) == 20
Обе функции имеют одинаковое определение, но обе делают разные вещи. Здесь нет повторяющегося кода. ;-)
Также бывает, что люди пишут повторяющиеся тесты, по существу, имеющие одно утверждение для каждой тестовой функции. Это безумие, и я видел, как люди это делают. Это является плохой практикой.
def test_multiply_1_and_3():
"""Assert that a multiplication of 1 and 3 is 3."""
assert multiply(1, 3) == 3
def test_multiply_1_and_7():
"""Assert that a multiplication of 1 and 7 is 7."""
assert multiply(1, 7) == 7
def test_multiply_3_and_4():
"""Assert that a multiplication of 3 and 4 is 12."""
assert multiply(3, 4) == 12
Представьте, что вы делаете это для 1000+ эффективных строк кода. Вместо этого вы тестируете для каждой функции:
def test_multiply_positive():
"""Assert that positive numbers can be multiplied."""
assert multiply(1, 3) == 3
assert multiply(1, 7) == 7
assert multiply(3, 4) == 12
def test_multiply_negative():
"""Assert that negative numbers can be multiplied."""
assert multiply(1, -3) == -3
assert multiply(-1, -7) == 7
assert multiply(-3, 4) == -12
Теперь, когда функции добавляются / удаляются, мне нужно только рассмотреть возможность добавления / удаления одной тестовой функции.
Возможно, вы заметили, я не применял for
петли. Это потому, что повторять некоторые вещи хорошо. Когда я применил бы циклы, код был бы намного короче. Но когда утверждение не выполняется, оно может запутать вывод, отображающий неоднозначное сообщение. Если это происходит , то ваши тесты будут менее полезны , и вы будете нуждаться в отладчике , чтобы проверить , где дела идут плохо.
assert multiply(1,3)
произойдет сбой, но вы также не получите отчет о неудачном тестированииassert multiply(3,4)
.def test_shuffle
выполняет два утверждения .assert multiply(*, *) == *
чтобы вы могли определитьassert_multiply
функцию. В текущем сценарии это не имеет значения по количеству строк и удобочитаемости, но при более длительных тестах вы можете повторно использовать сложные утверждения, фикстуры, код, генерирующий фикстуры и т. Д. Я не знаю, является ли это наилучшей практикой, но я обычно делаю это.Нет, это не так
Тесты имеют другое назначение, чем ваша реализация:
источник
Нет. DRY - это написание кода только один раз для выполнения конкретной задачи, тестирование - проверка правильности выполнения задачи. Это несколько похоже на алгоритм голосования, где очевидно, что использование одного и того же кода было бы бесполезным.
источник
Нет, конечная цель DRY на самом деле будет означать устранение всего производственного кода .
Если бы наши тесты могли быть идеальными спецификациями того, что мы хотим, чтобы система делала, нам просто нужно было бы автоматически генерировать соответствующий производственный код (или двоичные файлы), эффективно удаляя базу производственного кода как таковую.
На самом деле, именно этого и добиваются подходы, подобные модельно-ориентированной архитектуре, - единственного, созданного человеком источника правды, из которого все получается путем вычислений.
Я не думаю, что обратное (избавление от всех тестов) желательно, потому что:
источник
Потому что иногда повторяться - это нормально. Ни один из этих принципов не предназначен для использования в любых обстоятельствах без вопросов или контекста. Время от времени я писал тесты против наивной (и медленной) версии алгоритма, что является довольно явным нарушением СУХОГО, но определенно выгодно.
источник
Поскольку модульное тестирование подразумевает усложнение непреднамеренных изменений , иногда оно может также усложнять и преднамеренные изменения . Этот факт действительно связан с принципом СУХОЙ.
Например, если у вас есть функция,
MyFunction
которая вызывается в производственном коде только в одном месте, и вы пишете для нее 20 модульных тестов, вы можете легко получить в своем коде 21 место, где эта функция вызывается. Теперь, когда вам нужно изменить подписьMyFunction
, или семантику, или и то, и другое (потому что некоторые требования меняются), у вас есть 21 место для изменения вместо одного. И причина, действительно, является нарушением принципа DRY: вы повторяли (по крайней мере) один и тот же вызов функцииMyFunction
21 раз.Правильным подходом для такого случая является применение принципа DRY и к вашему тестовому коду: при написании 20 модульных тестов инкапсулируйте вызовы
MyFunction
в свои модульные тесты всего в нескольких вспомогательных функциях (в идеале только в одной), которые используются 20 юнит-тестов. В идеале в вашем коде нужно всего два места для вызова кодаMyFunction
: одно из вашего производственного кода и одно из ваших модульных тестов. Поэтому, когда вам придется изменить подпись наMyFunction
более поздний срок, у вас будет всего несколько мест для изменения в ваших тестах.«Несколько мест» по-прежнему больше, чем «одно место» (то, что вы получаете без юнит-тестов вообще), но преимущества использования юнит-тестов должны значительно перевесить преимущество меньшего количества кода для изменения (в противном случае вы выполняете юнит-тестирование полностью неправильно).
источник
Одной из самых больших проблем при создании программного обеспечения является учет требований; то есть, чтобы ответить на вопрос "что должно делать это программное обеспечение?" Программному обеспечению нужны точные требования для точного определения того, что должна делать система, но те, кто определяет потребности в программных системах и проектах, часто включают людей, у которых нет программного обеспечения или формального (математического) фона. Отсутствие строгости в определении требований вынудило разработку программного обеспечения найти способ проверки программного обеспечения на соответствие требованиям.
Команда разработчиков обнаружила, что переводит разговорное описание проекта в более строгие требования. Дисциплина тестирования объединилась в качестве контрольной точки для разработки программного обеспечения, чтобы преодолеть разрыв между тем, что клиент говорит, что он хочет, и тем, что программное обеспечение понимает, что он хочет. Как разработчики программного обеспечения, так и команда по качеству / тестированию формируют понимание (неформальной) спецификации, и каждый (независимо) пишет программное обеспечение или тесты, чтобы убедиться, что их понимание соответствует. Добавление другого человека для понимания (неточных) требований добавило вопросов и разных точек зрения, чтобы еще больше отточить точность требований.
Поскольку приемочное тестирование всегда проводилось, естественно было расширить роль тестирования для написания автоматических и модульных тестов. Проблема заключалась в том, что для тестирования требовалось нанять программистов, и таким образом вы сузили кругозор от обеспечения качества до программистов, проводящих тестирование.
Тем не менее, вы, вероятно, делаете тестирование неправильно, если ваши тесты мало отличаются от реальных программ. Мсди предложил бы сосредоточиться больше на том, что в тестах, и меньше на том, как.
Ирония заключается в том, что вместо того, чтобы фиксировать формальную спецификацию требований из разговорного описания, отрасль решила внедрить точечные тесты в виде кода для автоматизации тестирования. Вместо того, чтобы выдвигать формальные требования, на которые программное обеспечение могло бы быть построено, чтобы отвечать, использовался подход, состоящий в тестировании нескольких пунктов, а не подход к созданию программного обеспечения с использованием формальной логики. Это компромисс, но он был достаточно эффективным и относительно успешным.
источник
Если вы думаете, что ваш тестовый код слишком похож на ваш код реализации, это может указывать на то, что вы чрезмерно используете фальшивый фреймворк. Тестирование на основе имитации на слишком низком уровне может привести к тому, что настройка теста будет очень похожа на тестируемый метод. Попробуйте написать тесты более высокого уровня, которые с меньшей вероятностью сломаются, если вы измените свою реализацию (я знаю, что это может быть сложно, но если вы справитесь с этим, у вас будет более полезный набор тестов).
источник
Модульные тесты не должны включать дублирование тестируемого кода, как уже отмечалось.
Я хотел бы добавить, однако, что модульные тесты, как правило, не такие СУХИЕ, как «производственный» код, потому что установка имеет тенденцию быть похожей (но не идентичной) во всех тестах ... особенно если у вас есть значительное количество зависимостей, над которыми вы издеваетесь / притворяется.
Конечно, возможно преобразовать подобные вещи в общий метод настройки (или набор методов настройки) ... но я обнаружил, что эти методы настройки имеют тенденцию иметь длинные списки параметров и быть довольно хрупкими.
Так что будьте прагматичны. Если вы можете объединить установочный код, не ставя под угрозу удобство обслуживания, обязательно сделайте это. Но если альтернативой является сложный и хрупкий набор методов настройки, то небольшое количество повторений в ваших методах тестирования в порядке.
Местный евангелист TDD / BDD объясняет это следующим образом:
«Ваш рабочий код должен быть СУХИМ. Но все в порядке, чтобы ваши тесты были« влажными »».
источник
Это не так, тесты описывают варианты использования, в то время как код описывает алгоритм, который пропускает варианты использования, поэтому он является более общим. В TDD вы начинаете с написания сценариев использования (возможно, основанных на истории пользователя), а затем реализуете код, необходимый для передачи этих сценариев использования. Таким образом, вы пишете небольшой тест, небольшой кусок кода, и после этого вы рефакторинг, если необходимо, чтобы избавиться от повторений. Вот как это работает.
По тестам могут быть и повторы. Например, вы можете повторно использовать фиксаторы, код, генерирующий фикстуры, сложные утверждения и т. Д. Я обычно делаю это, чтобы предотвратить ошибки в тестах, но обычно я забываю сначала проверить, действительно ли тест провалился, и это действительно может испортить день. , когда вы ищете ошибку в коде в течение получаса и тест не соответствует действительности ... xD
источник