Я проверяю, что функция делает то, что ожидалось в списке. Итак, я хочу проверить
f(null) -> null
f(empty) -> empty
f(list with one element) -> list with one element
f(list with 2+ elements) -> list with the same number of elements, doing what expected
Для этого, каков наилучший подход?
- Тестирование всех случаев в одном (методическом) тесте под названием «WorksAsExpected»
- Размещение одного теста для каждого случая, таким образом, имея
- "WorksAsExpectedWhenNull"
- "WorksAsExpectedWhenEmpty"
- "WorksAsExpectedWhenSingleElement"
- "WorksAsExpectedWhenMoreElements"
- Другой выбор, о котором я не думал :-)
unit-testing
tdd
malarres
источник
источник
Ответы:
Простое эмпирическое правило, которое я использую для выполнения набора тестов в одном тестовом случае или во многих, заключается в следующем: включает ли оно только одну настройку?
Так что, если бы я проверял, что для нескольких элементов он обрабатывает все и выводит правильный результат, у меня может быть два или более утверждений, но мне нужно настроить список только один раз. Так что один контрольный пример - это хорошо.
В вашем случае, однако, я должен был бы установить нулевой список, пустой список и т. Д. Это несколько установок. Так что я бы определенно создал несколько тестов в этом случае.
Как уже упоминалось, эти «множественные тесты» могут существовать как один параметризованный тестовый случай; т. е. один и тот же контрольный пример выполняется с различными данными настройки. Ключ к знанию, является ли это жизнеспособным решением, лежит в других частях теста: «действие» и «утверждать». Если вы можете выполнять те же действия и утверждать для каждого набора данных, используйте этот подход. Если вы обнаружите, что добавляете
if
, например, другой код для разных частей этих данных, то это не решение проблемы. Используйте отдельные тестовые случаи в этом последнем случае.источник
Там есть компромисс. Чем больше вы соберете в одном тесте, тем больше у вас будет эффекта лука, пытающегося заставить его пройти. Другими словами, самый первый сбой останавливает этот тест. О других утверждениях вы не узнаете, пока не исправите первый сбой. Тем не менее, наличие множества модульных тестов, которые в основном похожи, за исключением настроенного кода, является большой занятой работой, просто чтобы выяснить, что некоторые работы написаны, а другие - нет.
Возможные инструменты, основанные на вашей структуре:
Assume.that()
просто пропускаете тест для данных, если он не проходит предварительное условие. Это позволяет вам определить «Работает как положено», а затем просто передать ему много данных. Когда вы просматриваете результаты, у вас есть запись для родительских тестов, а затем дополнительная запись для каждого фрагмента данных.Я не придерживаюсь строгого мнения, что
assert
в вашем тесте может быть только одно утверждение, но я налагаю ограничения на то, что все утверждения должны проверять постусловия одного действия. Если единственное различие между тестами - это данные, я бы предпочел использовать более продвинутые функции, основанные на данных, такие как параметризованные тесты или теории.Взвесьте ваши варианты, чтобы решить, каков наилучший результат. Я скажу, что «WorksAsExpectedWhenNull» принципиально отличается от любого из случаев, когда вы имеете дело с коллекцией, имеющей различное количество элементов.
источник
Это разные тестовые случаи, но код теста один и тот же. Поэтому использование параметризованных тестов является лучшим решением. Если ваша среда тестирования не поддерживает параметризацию, извлеките общий код в вспомогательную функцию и вызовите его из отдельных тестовых случаев.
Старайтесь избегать параметризации через цикл в одном тестовом примере, потому что это затрудняет определение того, какой набор данных вызвал ошибку.
В вашем цикле TDD красный-зеленый-рефакторинг вы должны добавлять один примерный набор данных за раз. Объединение нескольких тестовых случаев в параметризованный тест будет частью этапа рефакторинга.
Довольно другой подход - тестирование свойств . Вы должны создать различные (параметризованные) тесты, которые утверждают различные свойства вашей функции, без указания конкретных входных данных. Например, свойство может быть: для всех списков длина
xs
спискаys = f(xs)
равнаxs
. Среда тестирования будет генерировать интересные списки и случайные списки и утверждать, что ваши свойства сохраняются для всех из них. Это отходит от ручного задания примеров, поскольку при ручном выборе примеров могут пропустить интересные крайние случаи.источник
Уместно иметь по одному тесту для каждого случая, потому что тестирование одной концепции в каждом тесте является хорошим руководством, которое часто рекомендуется.
Смотрите этот пост: нормально ли иметь несколько утверждений в одном модульном тесте? , Там также есть актуальное и подробное обсуждение:
[...]
источник
На мой взгляд, это зависит от условий испытаний.
источник