В чем разница между yield и return в фикстурах PyTest?

«В чем разница между yield и return в фикстурах PyTest?» — вопрос из категории Фреймворки тестирования, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В PyTest yield и return используются в фикстурах для передачи данных в тест, но с фундаментальным отличием в возможности выполнить код очистки (teardown) после завершения теста.

Фикстура с return

  • Передаёт значение в тест и завершает работу.
  • Не предоставляет встроенного механизма для очистки. Если ресурс нужно закрыть, это делается отдельно (например, в финальной фазе теста или с помощью request.addfinalizer).

Фикстура с yield

  • Работает как генератор. Код до yield выполняется как установка (setup), а код после yield — как очистка (teardown).
  • Очистка выполняется гарантированно, даже если тест упал с ошибкой (assertion или exception).
  • Это идеальный способ для работы с ресурсами, требующими закрытия (файлы, соединения с БД, браузеры).

Практический пример с временным файлом:

import pytest
import os

# Фикстура с yield (рекомендуемый способ для ресурсов)
@pytest.fixture
def temp_config_file():
    # SETUP: Создаём временный файл перед тестом
    file_path = "/tmp/test_config.yaml"
    with open(file_path, 'w') as f:
        f.write("test_key: test_value")
    print("Файл создан")

    yield file_path  # Передаём путь к файлу в тест

    # TEARDOWN: Удаляем файл после теста (выполнится всегда)
    os.remove(file_path)
    print("Файл удалён")

# Фикстура с return и addfinalizer (альтернативный способ)
@pytest.fixture
def temp_config_file_v2(request):
    file_path = "/tmp/test_config_v2.yaml"
    with open(file_path, 'w') as f:
        f.write("test_key: test_value")
    print("Файл v2 создан")

    def cleanup():
        os.remove(file_path)
        print("Файл v2 удалён")

    request.addfinalizer(cleanup)  # Регистрируем функцию очистки
    return file_path  # Передаём путь

# Тест использует фикстуру

def test_read_config(temp_config_file):
    # В тест передан file_path
    with open(temp_config_file) as f:
        content = f.read()
    assert "test_key" in content
    # После этого теста PyTest автоматически выполнит os.remove(file_path)

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