Группировка тестов в pytest: Классы против простых функций

Я использую pytest для тестирования своего приложения. pytest поддерживает 2 подхода (что я знаю) о том, как писать тесты:

  1. В классах:

test_feature.py → класс TestFeature → def test_feature_sanity

  1. В функциях:

    test_feature.py → def test_feature_sanity

Нужен ли подход групповых тестов в классе? Разрешено ли использовать backstream встроенный модуль unittest? Какой подход вы бы сказали лучше и почему?

Заранее спасибо!

Ответ 1

Не существует строгих правил организации тестов в модулях против классов. Это вопрос личных предпочтений. Первоначально я пробовал организовывать тесты в классы, через некоторое время понял, что мне не нужен другой уровень организации. В настоящее время я просто собираю тестовые функции в модули (файлы).

Я мог видеть действительный прецедент, когда некоторые тесты могли быть логически организованы в один и тот же файл, но все еще имеют дополнительный уровень организации в классах (например, чтобы использовать привязку к классу). Но это также можно сделать, просто разбив на несколько модулей.

Ответ 2

Обычно в модульном тестировании объектом наших тестов является отдельная функция. То есть одна функция приводит к нескольким тестам. При чтении тестового кода полезно, чтобы тесты для одного модуля были каким-то образом сгруппированы (что также позволяет нам, например, запускать все тесты для определенной функции), поэтому у нас остается два варианта:

  1. Поместите все тесты для каждой функции в отдельный модуль
  2. Поместите все тесты для каждой функции в классе

При первом подходе нам все равно будет интересно сгруппировать все тесты, связанные с исходным модулем (например, utils.py), в некотором роде. Теперь, поскольку мы уже используем модули для группировки тестов для функции, это означает, что нам следует использовать пакет для группировки тестов для исходного модуля.

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

Во втором подходе мы вместо этого имели бы одну карту функции источника для одного тестового класса (например, my_function()TestMyFunction) и одну карту модуля источника для одного тестового модуля (например, utils.pytest_utils.py).

Возможно, это зависит от ситуации, но второй подход, то есть класс тестов для каждой тестируемой функции, мне кажется более понятным. Кроме того, если мы тестируем исходные классы/методы, мы могли бы просто использовать иерархию наследования тестовых классов и при этом сохранить один исходный модуль → отображение одного тестового модуля.

Наконец, еще одно преимущество любого подхода к простому плоскому файлу, содержащему тесты для нескольких функций, состоит в том, что с классами/модулями, уже определяющими, какая функция тестируется, вы можете иметь более подходящие имена для реальных тестов, например, test_does_x и test_handles_y вместо test_my_function_does_x и test_my_function_handles_y.