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

Фикстуры с параметрами в pytest создаются с помощью декоратора @pytest.fixture(params=[...]).

params - это список значений, которые будут переданы в фикстуру. Для каждого значения из списка фикстура будет вызвана один раз.

Использовать параметризованную фикстуру в тесте можно, просто указав ее имя в качестве аргумента тестовой функции. request объект внутри фикстуры предоставляет доступ к параметру через request.param.

Пример:


    import pytest

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

    def test_my_test(my_fixture):
        assert my_fixture > 0
  

В pytest фикстуры с параметрами позволяют запускать один и тот же тест с разными входными данными, делая тестирование более эффективным и всесторонним. Вот как это делается:

Определение параметризованной фикстуры:


  import pytest

  @pytest.fixture(params=[1, 2, 3])
  def my_fixture(request):
      return request.param
  
  • @pytest.fixture: Декоратор, определяющий фикстуру.
  • params=[1, 2, 3]: Ключевое слово params определяет список значений, которые будут использоваться для параметризации фикстуры. В данном случае, фикстура будет вызвана три раза, с request.param равным 1, 2 и 3 соответственно.
  • request: Объект request предоставляет информацию о текущем запросе фикстуры, включая доступ к параметрам через request.param.

Использование параметризованной фикстуры в тесте:


  def test_my_fixture(my_fixture):
      assert my_fixture > 0
      print(f"Текущее значение фикстуры: {my_fixture}")
  
  • test_my_fixture(my_fixture): Тестовая функция принимает фикстуру my_fixture как аргумент. pytest автоматически вызывает фикстуру и передает возвращаемое значение в тестовую функцию.
  • pytest запустит эту тестовую функцию трижды, один раз для каждого значения в списке params фикстуры.

Более сложные примеры с использованием ID для фикстур:


  import pytest

  @pytest.fixture(
      params=[(1, 2, 3), (4, 5, 6)],
      ids=["first_set", "second_set"]
  )
  def data_set(request):
      return request.param


  def test_data_set(data_set):
      a, b, c = data_set
      assert a + b + c > 0
      print(f"a: {a}, b: {b}, c: {c}")
  
  • ids=["first_set", "second_set"]: Ключевое слово ids позволяет задать понятные имена для каждого набора параметров. Это облегчает чтение результатов тестов.
  • В этом примере request.param будет сначала (1, 2, 3), а затем (4, 5, 6).

Параметризация с использованием pytest.mark.parametrize:

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


  import pytest

  @pytest.mark.parametrize(
      "input,expected",
      [
          (2, 4),
          (3, 9),
          (4, 16),
      ],
      ids=["two", "three", "four"]
  )
  def test_square(input, expected):
      assert input * input == expected
  
  • @pytest.mark.parametrize("input,expected", [...]): Декоратор parametrize принимает список кортежей. Каждый кортеж содержит входные данные для тестовой функции (в данном случае input и expected).
  • ids: Позволяет присвоить имена тестовым случаям.

Когда использовать параметризованные фикстуры против pytest.mark.parametrize?

  • Параметризованные фикстуры: Подходят, когда одна и та же логика инициализации (фиксации) требуется для нескольких тестов, и вы хотите переиспользовать её с разными параметрами. Это способствует DRY (Don't Repeat Yourself).
  • pytest.mark.parametrize: Подходит, когда параметризация специфична только для одного теста или небольшого набора тестов, и логика инициализации не требуется.

Преимущества параметризации:

  • Уменьшение дублирования кода: Избегаете повторения одного и того же теста с небольшими изменениями.
  • Повышение покрытия кода: Легко тестировать широкий спектр входных данных.
  • Улучшение читаемости тестов: Параметризация делает тесты более компактными и понятными.
0