Группировка тестов в pytest: Классы против простых функций
Я использую pytest для тестирования своего приложения. pytest поддерживает 2 подхода (что я знаю) о том, как писать тесты:
- В классах:
test_feature.py → класс TestFeature → def test_feature_sanity
- В функциях:
test_feature.py → def test_feature_sanity
Нужен ли подход групповых тестов в классе? Разрешено ли использовать backstream встроенный модуль unittest? Какой подход вы бы сказали лучше и почему?
Заранее спасибо!
Ответы
Ответ 1
Не существует строгих правил организации тестов в модулях против классов. Это вопрос личных предпочтений. Первоначально я пробовал организовывать тесты в классы, через некоторое время понял, что мне не нужен другой уровень организации. В настоящее время я просто собираю тестовые функции в модули (файлы).
Я мог видеть действительный прецедент, когда некоторые тесты могли быть логически организованы в один и тот же файл, но все еще имеют дополнительный уровень организации в классах (например, чтобы использовать привязку к классу). Но это также можно сделать, просто разбив на несколько модулей.
Ответ 2
Обычно в модульном тестировании объектом наших тестов является отдельная функция. То есть одна функция приводит к нескольким тестам. При чтении тестового кода полезно, чтобы тесты для одного модуля были каким-то образом сгруппированы (что также позволяет нам, например, запускать все тесты для определенной функции), поэтому у нас остается два варианта:
- Поместите все тесты для каждой функции в отдельный модуль
- Поместите все тесты для каждой функции в классе
При первом подходе нам все равно будет интересно сгруппировать все тесты, связанные с исходным модулем (например, utils.py
), в некотором роде. Теперь, поскольку мы уже используем модули для группировки тестов для функции, это означает, что нам следует использовать пакет для группировки тестов для исходного модуля.
В результате одна исходная функция отображается на один тестовый модуль, а один исходный модуль - на один тестовый пакет.
Во втором подходе мы вместо этого имели бы одну карту функции источника для одного тестового класса (например, my_function()
→ TestMyFunction
) и одну карту модуля источника для одного тестового модуля (например, utils.py
→ test_utils.py
).
Возможно, это зависит от ситуации, но второй подход, то есть класс тестов для каждой тестируемой функции, мне кажется более понятным. Кроме того, если мы тестируем исходные классы/методы, мы могли бы просто использовать иерархию наследования тестовых классов и при этом сохранить один исходный модуль → отображение одного тестового модуля.
Наконец, еще одно преимущество любого подхода к простому плоскому файлу, содержащему тесты для нескольких функций, состоит в том, что с классами/модулями, уже определяющими, какая функция тестируется, вы можете иметь более подходящие имена для реальных тестов, например, test_does_x
и test_handles_y
вместо test_my_function_does_x
и test_my_function_handles_y
.