15 промтов для написания unit-тестов и интеграционных тестов: шпаргалка для pytest и Jest

15 промтов для написания unit-тестов и интеграционных тестов: шпаргалка для pytest и Jest

Тестирование — это не роскошь, а необходимость в современной разработке. Согласно отчету State of Testing Report 2023 от PractiTest, организации, внедрившие автоматизированное тестирование, сокращают время на регрессионное тестирование в среднем на 50-70%. Однако написание тестов вручную отнимает часы, особенно когда кодовая база растет. Здесь на помощь приходят промты — готовые инструкции для AI-генерации тестов. В этой подборке я собрал 15 конкретных промтов для pytest, Jest и unittest, которые можно скопировать и сразу использовать. Каждый промт сопровождается примером и пояснением, чтобы вы могли адаптировать его под свой проект.

1. Промт для базового unit-теста функции на Python (pytest)

Когда использовать: Когда нужно быстро покрыть тестами простую функцию, например, математическую операцию или обработчик строк.

Промт:

Напиши unit-тесты на pytest для функции calculate_discount(price, discount_percent), которая возвращает цену со скидкой. Используй фикстуры для подготовки данных и параметризацию для тестирования граничных случаев: discount_percent = 0, 10, 50, 100. Проверь, что функция выбрасывает ValueError для отрицательной скидки.

Пример использования:

import pytest

@pytest.fixture
def base_price():
    return 1000

def calculate_discount(price, discount_percent):
    if discount_percent < 0:
        raise ValueError("Discount cannot be negative")
    return price - (price * discount_percent / 100)

@pytest.mark.parametrize("price, discount, expected", [
    (1000, 0, 1000),
    (1000, 10, 900),
    (1000, 50, 500),
    (1000, 100, 0),
])
def test_calculate_discount(base_price, discount, expected):
    assert calculate_discount(base_price, discount) == expected

def test_negative_discount():
    with pytest.raises(ValueError):
        calculate_discount(1000, -5)

Этот промт генерирует тесты с покрытием всех основных сценариев, включая ошибки.

2. Промт для тестирования класса с моками (unittest)

Когда использовать: Когда нужно изолировать тестируемый класс от внешних зависимостей, например, API или базы данных.

Промт:

Создай тесты на unittest для класса UserService с методом get_user(user_id), который вызывает внешний API через requests.get. Используй unittest.mock.patch для подмены requests.get. Проверь, что при статусе 200 возвращается словарь с данными, а при 404 — None. Добавь тест на выброс исключения при ошибке сети.

Пример использования:

import unittest
from unittest.mock import patch
import requests

class UserService:
    def get_user(self, user_id):
        response = requests.get(f"https://api.example.com/users/{user_id}")
        if response.status_code == 200:
            return response.json()
        elif response.status_code == 404:
            return None
        raise ConnectionError("Network error")

class TestUserService(unittest.TestCase):
    @patch('requests.get')
    def test_get_user_success(self, mock_get):
        mock_get.return_value.status_code = 200
        mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"}
        service = UserService()
        result = service.get_user(1)
        self.assertEqual(result, {"id": 1, "name": "Alice"})

    @patch('requests.get')
    def test_get_user_not_found(self, mock_get):
        mock_get.return_value.status_code = 404
        service = UserService()
        result = service.get_user(1)
        self.assertIsNone(result)

if __name__ == '__main__':
    unittest.main()

Промт помогает избежать реальных вызовов API, ускоряя тесты.

3. Промт для интеграционного теста базы данных (pytest)

Когда использовать: Когда нужно проверить взаимодействие кода с реальной базой данных (например, SQLite) без использования моков.

Промт:

Напиши интеграционный тест на pytest для функции add_user_to_db(name, email), которая вставляет запись в таблицу users. Используй фикстуру с временной базой данных SQLite, создаваемой через tmp_path. Проверь, что запись добавляется, а дубликат email вызывает IntegrityError.

Пример использования:

import pytest
import sqlite3

def add_user_to_db(name, email, db_path):
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", (name, email))
    conn.commit()
    conn.close()

@pytest.fixture
def db_path(tmp_path):
    path = tmp_path / "test.db"
    conn = sqlite3.connect(path)
    conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT UNIQUE)")
    conn.close()
    return path

def test_add_user_success(db_path):
    add_user_to_db("Alice", "alice@example.com", db_path)
    conn = sqlite3.connect(db_path)
    cursor = conn.execute("SELECT * FROM users")
    assert cursor.fetchone() == (1, "Alice", "alice@example.com")
    conn.close()

def test_add_duplicate_email(db_path):
    add_user_to_db("Alice", "alice@example.com", db_path)
    with pytest.raises(sqlite3.IntegrityError):
        add_user_to_db("Bob", "alice@example.com", db_path)

Этот тест проверяет реальное поведение базы данных, что важно для выявления ошибок целостности.

4. Промт для тестирования асинхронного кода (pytest-asyncio)

Когда использовать: Для тестирования async/await функций, например, в aiohttp или asyncio.

Промт:

Напиши асинхронные тесты на pytest с библиотекой pytest-asyncio для функции fetch_data(url), которая использует aiohttp.ClientSession для получения JSON. Используй фикстуру для создания сессии и мок aiohttp.ClientSession.get для возврата фиктивных данных.

Пример использования:

import pytest
from unittest.mock import AsyncMock, patch
import aiohttp

async def fetch_data(url, session):
    async with session.get(url) as response:
        return await response.json()

@pytest.mark.asyncio
async def test_fetch_data():
    mock_response = AsyncMock()
    mock_response.json.return_value = {"key": "value"}
    mock_session = AsyncMock()
    mock_session.get.return_value.__aenter__.return_value = mock_response

    result = await fetch_data("http://test.com", mock_session)
    assert result == {"key": "value"}

Промт помогает изолировать асинхронные вызовы, не создавая реальных HTTP-запросов.

5. Промт для тестирования исключений и краевых случаев (pytest)

Когда использовать: Когда нужно проверить, что функция корректно обрабатывает ошибки, пустые данные или граничные значения.

Промт:

Напиши тесты на pytest для функции divide(a, b), которая возвращает результат деления или выбрасывает ZeroDivisionError при b=0. Добавь параметризацию для b = 0, 1, -1, 0.001. Проверь, что при b=0 выбрасывается исключение, а при b=0.001 результат корректен.

Пример использования:

import pytest

def divide(a, b):
    if b == 0:
        raise ZeroDivisionError("division by zero")
    return a / b

@pytest.mark.parametrize("a, b, expected", [
    (10, 1, 10),
    (10, -1, -10),
    (10, 0.001, 10000),
])
def test_divide_success(a, b, expected):
    assert divide(a, b) == expected

def test_divide_by_zero():
    with pytest.raises(ZeroDivisionError):
        divide(10, 0)

Этот подход покрывает не только успешные сценарии, но и ошибки.

6. Промт для тестов с фикстурами и conftest.py (pytest)

Когда использовать: Когда нужно переиспользовать сложные настройки (например, подключение к тестовой БД) между несколькими тестовыми файлами.

Промт:

Создай фикстуру в файле conftest.py для pytest, которая подготавливает экземпляр класса Database с таблицей items. В тесте используй эту фикстуру для проверки метода get_item(item_id). Фикстура должна быть scope='function', чтобы каждый тест начинался с чистого состояния.

Пример использования:

# conftest.py
import pytest

class Database:
    def __init__(self):
        self.data = {1: "item1", 2: "item2"}
    def get_item(self, item_id):
        return self.data.get(item_id)

@pytest.fixture(scope='function')
def db():
    return Database()
# test_db.py
def test_get_item_existing(db):
    assert db.get_item(1) == "item1"

def test_get_item_missing(db):
    assert db.get_item(3) is None

Фикстуры делают тесты чище и уменьшают дублирование.

7. Промт для тестирования генераторов и итераторов (pytest)

Когда использовать: Для функций, возвращающих генераторы, например, при чтении больших файлов построчно.

Промт:

Напиши тесты на pytest для генератора read_lines(file_content), который принимает строку с переносами строк и возвращает каждую строку. Проверь, что генератор возвращает правильное количество строк и корректно обрабатывает пустой ввод.

Пример использования:

import pytest

def read_lines(content):
    for line in content.split('\n'):
        yield line

def test_read_lines_multiple():
    content = "line1\nline2\nline3"
    result = list(read_lines(content))
    assert result == ["line1", "line2", "line3"]

def test_read_lines_empty():
    content = ""
    result = list(read_lines(content))
    assert result == []

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

8. Промт для тестов с параметризацией и комбинациями (pytest.mark.parametrize)

Когда использовать: Когда нужно проверить функцию на большом наборе входных данных, например, для валидации форм.

Промт:

Напиши параметризованные тесты на pytest для функции validate_email(email), которая проверяет, что email содержит @ и точку. Используй комбинацию из 10 тестовых случаев: валидные email, email без @, email без точки, пустая строка.

Пример использования:

import pytest

def validate_email(email):
    return '@' in email and '.' in email

@pytest.mark.parametrize("email, expected", [
    ("user@example.com", True),
    ("user@example", False),
    ("userexample.com", False),
    ("", False),
    ("@example.com", True),
    ("user@.com", True),
])
def test_validate_email(email, expected):
    assert validate_email(email) == expected

Параметризация позволяет покрыть много случаев без дублирования кода.

9. Промт для тестирования Middleware в веб-фреймворках (pytest)

Когда использовать: Для проверки промежуточных слоев в Flask или Django.

Промт:

Напиши тест на pytest для Flask middleware, который проверяет, что каждый ответ содержит заголовок X-Request-Id. Используй тестовый клиент Flask и добавь middleware через app.before_request и app.after_request.

Пример использования:

import pytest
from flask import Flask, request, g

app = Flask(__name__)

@app.before_request
def before_request():
    g.request_id = request.headers.get('X-Request-Id', 'default')

@app.after_request
def after_request(response):
    response.headers['X-Request-Id'] = g.request_id
    return response

@app.route('/')
def index():
    return 'OK'

@pytest.fixture
def client():
    with app.test_client() as client:
        yield client

def test_middleware_adds_header(client):
    resp = client.get('/', headers={'X-Request-Id': '123'})
    assert resp.headers.get('X-Request-Id') == '123'

def test_middleware_default(client):
    resp = client.get('/')
    assert resp.headers.get('X-Request-Id') == 'default'

Этот тест гарантирует, что middleware работает корректно в разных сценариях.

10. Промт для тестирования конфигураций и переменных окружения (pytest)

Когда использовать: Когда код зависит от переменных окружения, например, DATABASE_URL или API_KEY.

Промт:

Напиши тесты на pytest для функции get_config(key), которая читает значение из переменных окружения через os.environ. Используй monkeypatch для установки и сброса переменных. Проверь, что возвращается значение по умолчанию, если переменная не задана.

Пример использования:

import pytest
import os

def get_config(key, default=None):
    return os.environ.get(key, default)

def test_get_config_exists(monkeypatch):
    monkeypatch.setenv('DATABASE_URL', 'postgres://localhost')
    assert get_config('DATABASE_URL') == 'postgres://localhost'

def test_get_config_default(monkeypatch):
    monkeypatch.delenv('DATABASE_URL', raising=False)
    assert get_config('DATABASE_URL', 'sqlite:///test.db') == 'sqlite:///test.db'

Monkeypatch — мощный инструмент для изоляции тестов от окружения.

11. Промт для тестирования производительности (pytest-benchmark)

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

Промт:

Напиши тест производительности на pytest с библиотекой pytest-benchmark для функции sort_list(data), которая сортирует список из 1000 элементов. Установи порог времени выполнения в 0.01 секунды.

Пример использования:

import pytest

def sort_list(data):
    return sorted(data)

def test_sort_performance(benchmark):
    data = list(range(1000, 0, -1))
    result = benchmark(sort_list, data)
    assert result == list(range(1, 1001))

Бенчмарки помогают отслеживать деградацию производительности.

12. Промт для тестирования HTTP-запросов (responses library)

Когда использовать: Для мокирования HTTP-запросов без реального соединения.

Промт:

Напиши тест на pytest с библиотекой responses для функции fetch_user(user_id), которая делает GET-запрос к https://api.example.com/users/{user_id}. Используй декоратор responses.activate для подмены ответа. Проверь, что возвращается JSON с данными.

Пример использования:

import pytest
import responses
import requests

def fetch_user(user_id):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json()

@responses.activate
def test_fetch_user():
    responses.add(
        responses.GET,
        "https://api.example.com/users/1",
        json={"id": 1, "name": "Alice"},
        status=200
    )
    result = fetch_user(1)
    assert result == {"id": 1, "name": "Alice"}

Библиотека responses упрощает тестирование внешних API.

13. Промт для тестирования декораторов (pytest)

Когда использовать: Когда нужно проверить, что декоратор правильно модифицирует поведение функции.

Промт:

Напиши тест на pytest для декоратора log_calls, который выводит в лог имя функции и аргументы. Используй фикстуру caplog для захвата логов. Проверь, что лог содержит имя функции и аргументы.

Пример использования:

import pytest
import logging

def log_calls(func):
    def wrapper(*args, **kwargs):
        logging.info(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
        return func(*args, **kwargs)
    return wrapper

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

def test_log_calls(caplog):
    caplog.set_level(logging.INFO)
    result = add(2, 3)
    assert result == 5
    assert "Calling add with args=(2, 3), kwargs={}" in caplog.text

Тесты для декораторов важны, так как они могут влиять на логику приложения.

14. Промт для тестирования файлового ввода-вывода (pytest)

Когда использовать: Для функций, работающих с файлами: чтение, запись, обработка CSV или JSON.

Промт:

Напиши тест на pytest для функции save_data_to_json(data, file_path), которая сохраняет словарь в JSON-файл. Используй фикстуру tmp_path для создания временного файла. Проверь, что файл создается и содержит правильные данные.

Пример использования:

import pytest
import json

def save_data_to_json(data, file_path):
    with open(file_path, 'w') as f:
        json.dump(data, f)

def test_save_data_to_json(tmp_path):
    data = {"name": "Alice", "age": 30}
    file_path = tmp_path / "data.json"
    save_data_to_json(data, file_path)
    with open(file_path, 'r') as f:
        loaded = json.load(f)
    assert loaded == data

tmp_path обеспечивает изоляцию и автоматическую очистку.

15. Промт для тестирования API с помощью pytest и Flask (интеграционные)

Когда использовать: Для интеграционного тестирования REST API, созданного на Flask.

Промт:

Напиши интеграционный тест на pytest для Flask-приложения с эндпоинтом POST /users, который принимает JSON с name и email. Используй тестовый клиент. Проверь, что при успешном создании возвращается статус 201 и JSON с id, а при отсутствии email — 400.

Пример использования:

import pytest
from flask import Flask, request, jsonify

app = Flask(__name__)
users_db = []

@app.route('/users', methods=['POST'])
def create_user():
    data = request.get_json()
    if not data or 'email' not in data:
        return jsonify({'error': 'Email is required'}), 400
    user = {'id': len(users_db) + 1, 'name': data.get('name'), 'email': data['email']}
    users_db.append(user)
    return jsonify(user), 201

@pytest.fixture
def client():
    with app.test_client() as client:
        yield client

def test_create_user_success(client):
    resp = client.post('/users', json={'name': 'Alice', 'email': 'alice@example.com'})
    assert resp.status_code == 201
    assert resp.get_json()['id'] == 1

def test_create_user_missing_email(client):
    resp = client.post('/users', json={'name': 'Bob'})
    assert resp.status_code == 400
    assert resp.get_json()['error'] == 'Email is required'

Интеграционные тесты проверяют полный цикл запроса и ответа.

Заключение

Эти 15 промтов покрывают большинство сценариев тестирования, с которыми сталкивается разработчик: от простых unit-тестов до интеграционных тестов с базами данных и API. Копируйте их, адаптируйте под свои проекты и экономьте время. Начните с первого промта и постепенно внедряйте остальные — ваша кодовая база станет надежнее, а регрессионные ошибки уйдут в прошлое. Если вы хотите углубиться в тему, рекомендую изучить официальную документацию pytest (https://docs.pytest.org) и Jest (https://jestjs.io/docs). Тестируйте с умом!

← Все статьи

Комментарии