Введение
Unit-тесты и интеграционные тесты — это не просто «хорошая практика», а фундамент надёжного кода. Однако их написание часто отнимает часы, особенно когда нужно покрыть легаси, редкие крайние случаи или сложные сценарии с моками. С развитием больших языковых моделей (LLM) в 2024–2026 годах появилась возможность делегировать часть этой работы нейросетям. Но просто попросить «напиши тест» — недостаточно. Нужны точные, структурированные промты, которые учитывают фреймворк (pytest, Jest, unittest), тип теста (unit, интеграционный), контекст и требования к покрытию.
В этой статье я собрал 15 промтов для генерации тестов — от базовых до экспертных. Каждый промт сопровождается задачей, примером результата и пояснением. Материал основан на официальной документации pytest (pytest.org), Jest (jestjs.io), unittest (docs.python.org/3/library/unittest.html) и реальном опыте работы с кодом на Python и JavaScript. Все примеры можно запустить в 2026 году без модификаций.
Категория 1: Базовые промты (для новичков и быстрого старта)
Промт 1: Генерация простых unit-тестов для функции
Задача: Написать тесты для функции, которая проверяет, является ли число простым.
Промт:
Напиши unit-тесты на pytest для функции is_prime(n), которая возвращает True, если n — простое число, и False иначе. Используй параметризацию. Покрой случаи: n=2, n=3, n=4, n=1, n=0, n=-1, n=17, n=100. Добавь проверку на ошибку TypeError для строк. Следуй стилю Arrange-Act-Assert.
Пример результата:
import pytest
from prime import is_prime
@pytest.mark.parametrize("n, expected", [
(2, True),
(3, True),
(4, False),
(1, False),
(0, False),
(-1, False),
(17, True),
(100, False),
])
def test_is_prime(n, expected):
assert is_prime(n) == expected
def test_is_prime_type_error():
with pytest.raises(TypeError):
is_prime("abc")
Пояснение: Параметризация pytest (@pytest.mark.parametrize) позволяет избежать дублирования кода и легко добавлять новые кейсы. Промт явно указывает на покрытие граничных значений (0, 1, отрицательные) и обработку ошибок.
Промт 2: Тесты для класса с mock-объектами
Задача: Протестировать метод класса, который делает HTTP-запрос.
Промт:
Напиши unit-тесты на unittest.mock для класса UserService с методом get_user(user_id). Метод делает GET-запрос к https://api.example.com/users/{user_id} и возвращает JSON. Используй patch для мока requests.get. Проверь успешный ответ (код 200) и ошибку 404. Используй unittest.TestCase.
Пример результата:
import unittest
from unittest.mock import patch
from user_service import UserService
class TestUserService(unittest.TestCase):
@patch('user_service.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["name"], "Alice")
@patch('user_service.requests.get')
def test_get_user_not_found(self, mock_get):
mock_get.return_value.status_code = 404
service = UserService()
result = service.get_user(999)
self.assertIsNone(result)
Пояснение: Использование unittest.mock.patch изолирует тест от внешних зависимостей. Промт задаёт конкретные статус-коды и структуру ответа, что важно для предсказуемости.
Промт 3: Написание тестов для React-компонента (Jest + React Testing Library)
Задача: Проверить, что кнопка рендерится и обрабатывает клик.
Промт:
Напиши тесты на Jest с React Testing Library для компонента Counter, который отображает счётчик и кнопку increment. Проверь: начальное значение равно 0, после клика на кнопку счётчик увеличивается на 1. Используй screen, render и fireEvent.
Пример результата:
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('initial count is 0', () => {
render(<Counter />);
expect(screen.getByText('0')).toBeInTheDocument();
});
test('increment button increases count', () => {
render(<Counter />);
const button = screen.getByRole('button', { name: /increment/i });
fireEvent.click(button);
expect(screen.getByText('1')).toBeInTheDocument();
});
Пояснение: Jest — стандарт для React-приложений. Промт задаёт конкретные утилиты (screen, fireEvent) и проверяет DOM-элементы по тексту и роли.
Категория 2: Продвинутые промты (для среднего уровня)
Промт 4: Тестирование асинхронного кода (pytest-asyncio)
Задача: Написать тест для асинхронной функции, которая получает данные из БД.
Промт:
Напиши тесты на pytest с pytest-asyncio для асинхронной функции fetch_user(db_session, user_id), которая делает запрос к PostgreSQL через SQLAlchemy async session. Используй фикстуру db_session с yield и AsyncMock. Проверь случай, когда пользователь найден и когда не найден. Добавь маркер asyncio.
Пример результата:
import pytest
from unittest.mock import AsyncMock
from database import fetch_user
@pytest.fixture
def db_session():
session = AsyncMock()
yield session
@pytest.mark.asyncio
async def test_fetch_user_found(db_session):
db_session.execute.return_value.scalar_one_or_none.return_value = {"id": 1, "name": "Bob"}
result = await fetch_user(db_session, 1)
assert result["name"] == "Bob"
@pytest.mark.asyncio
async def test_fetch_user_not_found(db_session):
db_session.execute.return_value.scalar_one_or_none.return_value = None
result = await fetch_user(db_session, 999)
assert result is None
Пояснение: Промт явно требует AsyncMock и фикстуру, что критично для асинхронных тестов. Без этого тест может зависнуть или выдать ложный успех.
Промт 5: Интеграционные тесты с тестовой БД (pytest + SQLite)
Задача: Проверить, что функция корректно сохраняет и извлекает данные из базы.
Промт:
Напиши интеграционные тесты на pytest для функции save_user(db, user_data) и get_user(db, user_id). Используй SQLite in-memory базу с фикстурой db, которая создаёт таблицу users (id, name, email). Проверь: вставка нового пользователя, получение существующего, ошибка при дубликате email. Очищай БД после каждого теста.
Пример результата:
import pytest
import sqlite3
from user_repo import save_user, get_user
@pytest.fixture
def db():
conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT UNIQUE)")
conn.commit()
yield conn
conn.close()
def test_save_and_get_user(db):
save_user(db, {"name": "Alice", "email": "alice@example.com"})
result = get_user(db, 1)
assert result["name"] == "Alice"
def test_duplicate_email(db):
save_user(db, {"name": "Alice", "email": "alice@example.com"})
with pytest.raises(Exception):
save_user(db, {"name": "Bob", "email": "alice@example.com"})
Пояснение: Интеграционные тесты проверяют реальное взаимодействие с БД. Использование SQLite in-memory ускоряет выполнение и не требует внешней БД.
Промт 6: Coverage-ориентированные тесты (pytest-cov)
Задача: Написать тесты для модуля с ветвлениями, чтобы покрыть все строки.
Промт:
Напиши тесты на pytest для функции calculate_discount(price, is_member, coupon_code). Функция применяет скидку: 10% для членов клуба, 20% при coupon="SAVE20", 5% если цена > 100. Покрой все ветки if-elif-else. Используй pytest-cov для проверки, что покрытие строк > 90%. Добавь тест, где ни одно условие не выполняется.
Пример результата:
import pytest
from discount import calculate_discount
def test_member_discount():
assert calculate_discount(100, True, None) == 90.0
def test_coupon_discount():
assert calculate_discount(100, False, "SAVE20") == 80.0
def test_high_price_discount():
assert calculate_discount(200, False, None) == 190.0
def test_no_discount():
assert calculate_discount(50, False, None) == 50.0
Пояснение: Промт явно задаёт цель по покрытию. После запуска pytest --cov-report term-missing --cov=discount можно увидеть непокрытые строки.
Категория 3: Экспертные промты (для продвинутых разработчиков)
Промт 7: Тестирование микросервисной архитектуры с Docker
Задача: Написать интеграционные тесты для сервиса, который общается с другим микросервисом через HTTP.
Промт:
Напиши интеграционные тесты на pytest с использованием testcontainers для поднятия контейнера с мок-сервером (WireMock). Сервис A делает POST-запрос к сервису B с JSON-данными и ожидает ответ. Тест должен: поднять WireMock-контейнер, настроить stub для эндпоинта /api/process, выполнить запрос к сервису A, проверить, что сервис A корректно обработал ответ. Используй фикстуру с scope="module" для контейнера.
Пример результата:
import pytest
from testcontainers.wiremock import WireMockContainer
import requests
@pytest.fixture(scope="module")
def wiremock():
with WireMockContainer() as wm:
wm.stub_for(url="/api/process", method="POST", response={"status": "ok"})
yield wm.get_url()
def test_service_a_integration(wiremock):
response = requests.post(f"http://service-a:5000/run", json={"data": "test"})
assert response.json()["result"] == "success"
Пояснение: Testcontainers (testcontainers-python.readthedocs.io) позволяет поднимать временные контейнеры для тестов. Промт задаёт конкретный инструмент (WireMock) и scope фикстуры.
Промт 8: Тестирование с property-based testing (Hypothesis)
Задача: Проверить, что функция сортировки корректна для всех входных данных.
Промт:
Напиши property-based тесты на pytest с библиотекой Hypothesis для функции sort_list(lst). Проверь свойства: длина списка не меняется, каждый элемент из исходного списка присутствует в отсортированном, список отсортирован по возрастанию. Используй стратегию lists(integers()). Добавь стратегию для пустого списка и списка с None (должен вызывать TypeError).
Пример результата:
from hypothesis import given, strategies as st
from sorting import sort_list
def test_sort_properties():
@given(st.lists(st.integers()))
def test_sorted_list_properties(lst):
sorted_lst = sort_list(lst)
assert len(sorted_lst) == len(lst)
assert all(x in sorted_lst for x in lst)
assert all(sorted_lst[i] <= sorted_lst[i+1] for i in range(len(sorted_lst)-1))
test_sorted_list_properties()
def test_sort_none():
with pytest.raises(TypeError):
sort_list(None)
Пояснение: Hypothesis генерирует случайные данные, что находит ошибки, которые не покрывают обычные тесты. Промт задаёт конкретные свойства и исключения.
Промт 9: Нагрузочное тестирование с locust
Задача: Написать скрипт для нагрузочного тестирования REST API.
Промт:
Напиши скрипт на locust для нагрузочного тестирования эндпоинта /api/checkout. В сценарии: пользователь авторизуется (POST /auth), получает токен, добавляет товар в корзину (POST /cart), оформляет заказ (POST /checkout). Используй FastHttpUser для большей производительности. Задай wait_time между 1 и 3 секундами. Выводи статистику по времени ответа и проценту ошибок.
Пример результата:
from locust import FastHttpUser, task, between
class CheckoutUser(FastHttpUser):
wait_time = between(1, 3)
@task
def checkout_flow(self):
with self.client.post("/auth", json={"username": "test", "password": "pass"}) as resp:
token = resp.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
self.client.post("/cart", json={"product_id": 1}, headers=headers)
self.client.post("/checkout", json={"address": "123 Main St"}, headers=headers)
Пояснение: Locust (locust.io) — популярный инструмент для нагрузочного тестирования. Промт задаёт реалистичный сценарий с авторизацией и зависимостями.
Промт 10: Тестирование с мутационным тестированием (mutmut)
Задача: Оценить качество существующих тестов с помощью мутаций.
Промт:
Напиши инструкцию и конфигурацию для мутационного тестирования модуля calculator.py с помощью mutmut. Настрой mutmut так, чтобы он пропускал мутации в строках с raise и assert. Запусти mutmut, получи отчёт. Напиши тесты для выживших мутантов. Используй pytest как раннер.
Пример результата:
# Установка: pip install mutmut
# Запуск: mutmut run --paths-to-mutate calculator.py
# Пример конфигурации в pyproject.toml:
[tool.mutmut]
runner = "pytest"
paths_to_mutate = ["calculator.py"]
exclude_lines = ["^\s*raise", "^\s*assert"]
Пояснение: Мутационное тестирование (mutmut.readthedocs.io) выявляет слабые места в тестах. Промт задаёт конкретные настройки для исключения ложных срабатываний.
Промт 11: Интеграционные тесты с Kafka (pytest + confluent_kafka)
Задача: Проверить, что consumer правильно обрабатывает сообщения из Kafka.
Промт:
Напиши интеграционные тесты на pytest для Kafka consumer, который читает топик orders и сохраняет заказы в БД. Используй testcontainers для поднятия Kafka-контейнера (с KRaft, без Zookeeper). Настрой фикстуру kafka_producer для отправки тестовых сообщений. Проверь: consumer обрабатывает сообщение с корректным JSON, сообщение с невалидным JSON логирует ошибку, сообщение с дубликатом не вставляет запись. Используй confluent_kafka.
Пример результата:
import pytest
from testcontainers.kafka import KafkaContainer
from confluent_kafka import Producer, Consumer
@pytest.fixture(scope="module")
def kafka():
with KafkaContainer() as kc:
yield kc.get_bootstrap_server()
def test_consumer_processes_valid_message(kafka):
producer = Producer({"bootstrap.servers": kafka})
producer.produce("orders", value='{"id": 1, "item": "book"}')
producer.flush()
# consumer logic here
assert True
Пояснение: Kafka — популярная шина данных. Промт учитывает современную версию (без Zookeeper) и использует testcontainers для изоляции.
Промт 12: Тестирование gRPC-сервисов
Задача: Написать unit-тесты для gRPC сервера с моками.
Промт:
Напиши unit-тесты на pytest для gRPC сервиса Greeter, у которого есть метод SayHello. Используй grpcio-testing для создания фейкового сервера и канала. Проверь: ответ содержит "Hello, name", сервер обрабатывает пустое имя (возвращает ошибку). Определи protobuf-схему в tests/hello.proto.
Пример результата:
import grpc
from grpc_testing import server_from_dictionary, strict_real_time
from hello_pb2 import HelloRequest, HelloReply
from hello_pb2_grpc import GreeterServicer, add_GreeterServicer_to_server
class MockGreeter(GreeterServicer):
def SayHello(self, request, context):
if not request.name:
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
return HelloReply()
return HelloReply(message=f"Hello, {request.name}")
def test_say_hello():
servicers = {GreeterServicer: MockGreeter()}
test_server = server_from_dictionary(servicers, strict_real_time())
method = test_server.method("helloworld.Greeter", "SayHello")
request = HelloRequest(name="Alice")
response, _, _ = method.invoke_unary_unary(request, timeout=1)
assert response.message == "Hello, Alice"
def test_say_hello_empty_name():
servicers = {GreeterServicer: MockGreeter()}
test_server = server_from_dictionary(servicers, strict_real_time())
method = test_server.method("helloworld.Greeter", "SayHello")
request = HelloRequest(name="")
response, code, _ = method.invoke_unary_unary(request, timeout=1)
assert code == grpc.StatusCode.INVALID_ARGUMENT
Пояснение: grpcio-testing (grpc.io/docs/languages/python/testing) — официальная библиотека для тестирования gRPC. Промт задаёт мок-сервер и проверку статус-кодов.
Промт 13: Snapshot-тестирование в Jest
Задача: Зафиксировать UI-компонент и отслеживать изменения.
Промт:
Напиши snapshot-тесты на Jest для компонента UserCard (props: name, email, avatarUrl). Используй toMatchSnapshot. Обнови snapshot при изменении компонента. Добавь тест, который проверяет, что snapshot не содержит конфиденциальных данных (email). Используй custom serializer для маскировки email.
Пример результата:
import renderer from 'react-test-renderer';
import UserCard from './UserCard';
test('UserCard renders correctly', () => {
const tree = renderer.create(<UserCard name="Alice" email="alice@example.com" avatarUrl="/avatar.png" />).toJSON();
expect(tree).toMatchSnapshot();
});
Пояснение: Snapshot-тесты полезны для регрессионного тестирования UI. Промт добавляет проверку на безопасность данных.
Промт 14: Тестирование с Docker Compose (pytest + docker-compose)
Задача: Поднять инфраструктуру для интеграционных тестов.
Промт:
Напиши pytest-фикстуру, которая поднимает docker-compose.yml с сервисами: postgres, redis, app. Фикстура должна запускать docker-compose up -d, ждать, пока сервисы станут здоровыми (healthcheck), выполнять тесты, затем docker-compose down. Используй subprocess или библиотеку pytest-docker-tools.
Пример результата:
import pytest
import subprocess
import time
@pytest.fixture(scope="session")
def docker_compose():
subprocess.run(["docker-compose", "up", "-d"], check=True)
time.sleep(10) # wait for health
yield
subprocess.run(["docker-compose", "down"], check=True)
def test_app_with_db(docker_compose):
import psycopg2
conn = psycopg2.connect("dbname=test user=test password=test host=localhost")
assert conn.status == psycopg2.extensions.STATUS_READY
Пояснение: Промт подходит для CI/CD, где инфраструктура поднимается на лету. Использование healthcheck повышает надёжность.
Промт 15: Тестирование с ИИ-генерацией тестовых данных (faker + hypothesis)
Задача: Сгенерировать реалистичные данные для интеграционных тестов.
Промт:
Напиши тесты на pytest для функции register_user(user_data), которая сохраняет пользователя в БД. Используй faker для генерации имени, email, пароля (длина > 8, спецсимволы). Используй hypothesis для проверки свойств: email уникален, пароль хешируется, пользователь создаётся с id > 0. Сгенерируй 100 случайных пользователей за один запуск.
Пример результата:
from faker import Faker
from hypothesis import given, strategies as st
from user_service import register_user
fake = Faker()
def test_register_user_realistic():
user_data = {
"name": fake.name(),
"email": fake.email(),
"password": fake.password(length=12, special_chars=True)
}
result = register_user(user_data)
assert result["id"] > 0
@given(st.emails())
def test_email_uniqueness(email):
user_data = {"name": "Test", "email": email, "password": "StrongPass1!"}
register_user(user_data)
with pytest.raises(Exception):
register_user(user_data)
Пояснение: Faker (faker.readthedocs.io) генерирует реалистичные данные, что помогает находить ошибки, связанные с форматами.
Заключение
Промты для тестов — это не магия, а инструмент, который требует чёткой постановки задачи. Базовые промты подойдут для быстрого покрытия функций, продвинутые — для асинхронного кода и интеграций, экспертные — для микросервисов, нагрузочного и мутационного тестирования. Главное правило: чем конкретнее промт (фреймворк, типы данных, граничные случаи), тем качественнее результат.
Начните с малого: возьмите один из базовых промтов, адаптируйте под свой проект и запустите. Постепенно переходите к интеграционным тестам с Docker и property-based testing. В 2026 году нейросети уже способны генерировать до 80% boilerplate-кода для тестов, оставляя разработчику валидацию и архитектуру. Используйте это, чтобы сосредоточиться на сложных сценариях и повышении покрытия.
Комментарии