Как реализовать параметрические тесты в `pytest` с использованием фикстуры?

Параметризация в `pytest` с использованием фикстур позволяет предоставить различные значения для тестов, основываясь на данных, предоставленных фикстурой. Это достигается с помощью `pytest.mark.parametrize`. Фикстура возвращает список или кортеж значений, которые используются как параметры для тестов.

Пример:

  import pytest

  @pytest.fixture(params=[1, 2, 3])
  def my_fixture(request):
      return request.param

  @pytest.mark.parametrize("expected_result", [2, 4, 6])
  def test_my_function(my_fixture, expected_result):
      assert my_fixture * 2 == expected_result
  
Здесь `my_fixture` параметризована с значениями `1, 2, 3`. `test_my_function` использует значения из `my_fixture` и из `@pytest.mark.parametrize("expected_result", [2, 4, 6])`, создавая 3 теста, каждый с комбинацией значений фикстуры и параметризованного аргумента.

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

  1. Создание фикстуры: Фикстура будет предоставлять параметризированные данные для тестов. Мы определяем её, используя декоратор @pytest.fixture и параметризуем с помощью аргумента params.
  2. Параметризация фикстуры: Указываем список значений (или более сложных объектов) в params. pytest создаст отдельный экземпляр фикстуры для каждого значения в params.
  3. Использование фикстуры в тесте: Добавляем имя фикстуры в качестве аргумента тестовой функции. pytest автоматически передаст соответствующий экземпляр фикстуры в тест.
  4. Изменение ID (необязательно, но рекомендуется): Чтобы сделать вывод более понятным, можно использовать ids при параметризации фикстуры. ids - это список строк, которые будут использоваться в качестве идентификаторов для каждого параметризованного случая. Если ids не указан, pytest сгенерирует идентификаторы автоматически.

Пример:


 import pytest

 # Фикстура, предоставляющая параметризированные данные
 @pytest.fixture(params=[(1, 2, 3), (4, 5, 9), (7, 8, 15)], ids=["case1", "case2", "case3"])
 def parameterized_data(request):
  return request.param

 # Тест, использующий фикстуру
 def test_addition(parameterized_data):
  a, b, expected = parameterized_data
  assert a + b == expected

 # Более сложный пример с классами
 class MyClass:
  def __init__(self, x, y):
   self.x = x
   self.y = y

  def add(self):
   return self.x + self.y


 @pytest.fixture(params=[
  (MyClass(1, 2), 3),
  (MyClass(4, 5), 9),
 ], ids=["class_case_1", "class_case_2"])
 def my_class_data(request):
  return request.param

 def test_my_class_addition(my_class_data):
  instance, expected = my_class_data
  assert instance.add() == expected


  # Фикстура, параметризованная функцией
 def get_data():
    return [(1,2,3), (4,5,9)]


 @pytest.fixture(params=get_data())
 def function_parameterized_data(request):
   return request.param


 def test_function_parameterized(function_parameterized_data):
    a,b,expected = function_parameterized_data
    assert a + b == expected
 

Объяснение:

  • В первом примере parameterized_data – это фикстура, которая возвращает кортежи (a, b, expected) для каждого тестового случая. Параметр ids делает вывод более читаемым.
  • test_addition – это тест, который принимает parameterized_data в качестве аргумента. pytest автоматически вызывает фикстуру для каждого набора параметров и передает возвращаемое значение в тестовую функцию.
  • Во втором примере демонстрируется использование класса в качестве одного из параметров.
  • В третьем примере параметризация происходит с помощью функции. get_data возвращает список параметров.

Запуск тестов:

При запуске pytest с этим кодом, он выполнит test_addition три раза, используя разные значения, предоставленные фикстурой parameterized_data. Аналогично, test_my_class_addition выполнится два раза. Вывод будет включать ID, которые мы указали, облегчая идентификацию каждого тестового прогона.

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

0