Использовал ли ты контекстные менеджеры в Python для тестирования?

«Использовал ли ты контекстные менеджеры в Python для тестирования?» — вопрос из категории Python, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, постоянно использую контекстные менеджеры в автотестах на Python для гарантированного управления ресурсами и состояниями. Это критически важно для создания стабильных и изолированных тестов.

Основные сценарии применения в тестировании:

  1. Работа с временными файлами и данными: Использую tempfile.TemporaryDirectory и tempfile.NamedTemporaryFile, чтобы файлы удалялись автоматически после теста, даже если он упал.

    import tempfile
    import json
    
    def test_data_is_saved_correctly():
        with tempfile.NamedTemporaryFile(mode='w+', suffix='.json', delete=False) as tmp:
            # Тест записывает данные во временный файл
            json.dump({"test": "data"}, tmp)
            tmp.flush()
            # ... здесь код, который читает и проверяет файл
        # Файл автоматически удаляется после выхода из блока `with`
  2. Мокирование и патчинг (с помощью unittest.mock): Контекстный менеджер patch позволяет временно подменить объект только на время выполнения теста.

    from unittest.mock import patch
    
    def test_external_api_call():
        with patch('requests.get') as mock_get:
            # Настраиваем мок на время этого теста
            mock_get.return_value.status_code = 200
            mock_get.return_value.json.return_value = {"ok": true}
    
            # Вызов тестируемой функции, которая использует requests.get
            result = function_under_test()
            assert result is True
            # После выхода из `with` оригинальный requests.get восстанавливается
  3. Управление соединениями с БД или внешними сервисами: Пишу собственные контекстные менеджеры или использую предоставляемые фреймворками (например, в Django/Pytest) для работы с тестовыми транзакциями, чтобы не засорять базу данных.

  4. Замер времени выполнения (для performance-тестов):

    import time
    from contextlib import contextmanager
    
    @contextmanager
    def timer():
        start = time.perf_counter()
        yield
        end = time.perf_counter()
        print(f"Time elapsed: {end - start:.4f} seconds")
    
    def test_function_performance():
        with timer():
            # Выполняем операцию, время которой хотим замерить
            heavy_operation()

Использование with гарантирует, что ресурсы будут освобождены, а состояние окружения — восстановлено, что делает тесты более надежными и идемпотентными.