Тестирование

12. Тестирование #

Тестирование — важный этап разработки, обеспечивающий стабильность и надежность кода. Python предлагает встроенные и сторонние инструменты для создания тестов.


12.1. Введение в модуль unittest #

unittest — стандартная библиотека Python для тестирования.

Основные понятия: #

  1. Тест-кейс: отдельный тест, описывающий определенное поведение.
  2. Тестовый набор (test suite): группа тестов.
  3. Тестовый запуск (test runner): инструмент для выполнения тестов.

Пример тест-кейса #

import unittest

def add(a, b):
    return a + b

class TestMathOperations(unittest.TestCase):
    def test_add_positive_numbers(self):
        self.assertEqual(add(3, 5), 8)

    def test_add_negative_numbers(self):
        self.assertEqual(add(-3, -5), -8)

    def test_add_mixed_sign_numbers(self):
        self.assertEqual(add(3, -5), -2)

if __name__ == "__main__":
    unittest.main()
Команды для запуска: #
  1. Запуск теста из файла:
    python test_file.py
    
  2. Запуск всех тестов из директории:
    python -m unittest discover
    

12.2. Использование pytest #

pytest — мощная и простая в использовании библиотека для тестирования.

Установка #

pip install pytest

Пример теста #

test_math_operations.py:

def add(a, b):
    return a + b

def test_add_positive_numbers():
    assert add(3, 5) == 8

def test_add_negative_numbers():
    assert add(-3, -5) == -8

def test_add_mixed_sign_numbers():
    assert add(3, -5) == -2
Запуск тестов #
pytest

Особенности pytest: #

  • Автоматический поиск тестов: все файлы с именами test_*.py или *_test.py автоматически подхватываются.

  • Маркеры тестов: позволяют группировать тесты.

    import pytest
    
    @pytest.mark.slow
    def test_slow_function():
        assert True
    

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

    pytest -m slow
    

Фикстуры #

Фикстуры упрощают подготовку данных для тестов.

import pytest

@pytest.fixture
def sample_data():
    return {"a": 3, "b": 5}

def test_add_with_fixture(sample_data):
    result = sample_data["a"] + sample_data["b"]
    assert result == 8

12.3. Мокирование и тестирование асинхронного кода #

Мокирование с использованием unittest.mock #

Мокирование позволяет заменять реальные объекты тестируемого кода их имитацией.

Пример: #
from unittest.mock import Mock

def fetch_data(api):
    return api.get_data()

def test_fetch_data():
    mock_api = Mock()
    mock_api.get_data.return_value = {"key": "value"}
    result = fetch_data(mock_api)
    assert result == {"key": "value"}

Тестирование асинхронного кода с pytest-asyncio #

Установка #
pip install pytest-asyncio
Пример теста #
import asyncio
import pytest

async def async_add(a, b):
    await asyncio.sleep(1)
    return a + b

@pytest.mark.asyncio
async def test_async_add():
    result = await async_add(3, 5)
    assert result == 8

Инструменты для асинхронного мокирования #

Для мокирования асинхронных функций можно использовать AsyncMock.

Пример: #
from unittest.mock import AsyncMock

async def fetch_data(api):
    return await api.get_data()

def test_fetch_data():
    mock_api = AsyncMock()
    mock_api.get_data.return_value = {"key": "value"}
    result = asyncio.run(fetch_data(mock_api))
    assert result == {"key": "value"}

Рекомендации #

  1. Используйте unittest для простых проектов, где важна встроенность в стандартную библиотеку.
  2. Применяйте pytest для крупных проектов благодаря его гибкости и расширяемости.
  3. При тестировании кода, связанного с внешними сервисами, используйте мокирование, чтобы избежать зависимости от этих сервисов.
  4. Для асинхронного кода выбирайте инструменты, совместимые с asyncio, например, pytest-asyncio и AsyncMock.