AI QA-инженер — цифровой сотрудник для тестирования
AI QA-инженер автоматизирует разработку тест-кейсов, написание автотестов, анализ результатов тестирования, расследование упавших тестов и генерацию отчётов. Используется как дополнение к реальной QA-команде для ускорения покрытия и снижения рутинной нагрузки.
Генерация тест-кейсов из требований
from openai import AsyncOpenAI
from pydantic import BaseModel
from typing import Literal
client = AsyncOpenAI()
class TestCase(BaseModel):
id: str
title: str
category: Literal["positive", "negative", "edge_case", "security", "performance"]
preconditions: list[str]
steps: list[str]
expected_result: str
priority: Literal["critical", "high", "medium", "low"]
test_data: dict
async def generate_test_cases(
feature_description: str,
acceptance_criteria: list[str],
existing_test_cases: list[str] = None,
) -> list[TestCase]:
existing_context = f"\nУже существующие тест-кейсы (не дублировать):\n{chr(10).join(existing_test_cases[:10])}" if existing_test_cases else ""
response = await client.beta.chat.completions.parse(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Ты — QA-инженер с опытом 8 лет.
Создавай тест-кейсы по стандарту IEEE 829.
Обязательно включи: happy path, граничные значения, негативные сценарии, безопасность.
Тест-данные должны быть конкретными (не 'тестовые данные').{existing_context}"""
}, {
"role": "user",
"content": f"""Фича: {feature_description}
Acceptance criteria:
{chr(10).join(f'- {ac}' for ac in acceptance_criteria)}""",
}],
response_format=list[TestCase],
temperature=0.3,
)
return response.choices[0].message.parsed
Генерация автотестов
class AutotestGenerator:
async def generate_pytest_tests(
self,
test_cases: list[TestCase],
api_schema: dict,
existing_fixtures: str = "",
) -> str:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Генерируй Python pytest тесты.
Правила:
- Используй parametrize для похожих тест-кейсов
- Используй existing fixtures: {existing_fixtures[:200] if existing_fixtures else 'нет'}
- Описательные имена функций: test_should_X_when_Y
- Assert с понятным сообщением об ошибке
- Изолированные тесты (каждый тест независим)
API Schema: {json.dumps(api_schema, indent=2)[:1000]}"""
}, {
"role": "user",
"content": f"Сгенерируй pytest тесты для:\n{json.dumps([tc.model_dump() for tc in test_cases], ensure_ascii=False, indent=2)}",
}],
temperature=0.2,
)
return response.choices[0].message.content
async def generate_playwright_tests(
self,
test_cases: list[TestCase],
page_object_models: str = "",
) -> str:
"""Генерирует Playwright E2E тесты"""
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Генерируй Playwright тесты на TypeScript.
Используй Page Object Model. Доступные POM: {page_object_models[:300] if page_object_models else 'нет'}
Каждый тест — независим. Данные — через test.use({{}}) или constants."""
}, {
"role": "user",
"content": json.dumps([tc.model_dump() for tc in test_cases], ensure_ascii=False),
}],
)
return response.choices[0].message.content
Анализ упавших тестов
class FailedTestAnalyzer:
async def analyze_failure(
self,
test_name: str,
error_message: str,
stacktrace: str,
recent_commits: list[dict],
test_history: list[dict],
) -> dict:
"""Анализирует причину падения теста и предлагает исправление"""
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": "Ты — Senior QA Engineer. Анализируй провалившиеся тесты: определяй root cause, отличай flaky от реальных ошибок, предлагай конкретные fix."
}, {
"role": "user",
"content": f"""Провалившийся тест: {test_name}
Ошибка: {error_message}
Stacktrace: {stacktrace[:1000]}
Недавние коммиты: {json.dumps(recent_commits[:5], ensure_ascii=False)}
История теста (последние 10 запусков): {[r['status'] for r in test_history[-10:]]}
Определи: 1) тип проблемы (flaky/regression/env), 2) вероятную причину, 3) предложи исправление.""",
}],
)
return {
"analysis": response.choices[0].message.content,
"is_flaky": self.detect_flaky_pattern(test_history),
"likely_cause": self.extract_root_cause(error_message, stacktrace),
}
def detect_flaky_pattern(self, history: list[dict]) -> bool:
"""Тест flaky если чередует pass/fail без очевидного паттерна"""
statuses = [r["status"] for r in history[-10:]]
passes = statuses.count("passed")
fails = statuses.count("failed")
# Flaky: оба статуса встречаются, нет явной деградации
return passes >= 2 and fails >= 2 and statuses[-1] != "failed" * 3
Отчёт о покрытии
class CoverageReporter:
async def generate_coverage_report(
self,
coverage_data: dict,
test_cases: list[dict],
code_diff: str = "",
) -> str:
report = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": "Создай отчёт о тестовом покрытии для команды. Выдели: непокрытые критические пути, рекомендации по приоритетным тестам для написания."
}, {
"role": "user",
"content": f"""Coverage: {json.dumps(coverage_data, indent=2)[:1000]}
Количество тест-кейсов: {len(test_cases)}, из них automated: {sum(1 for t in test_cases if t.get('automated'))}
Изменения кода (diff): {code_diff[:500] if code_diff else 'не предоставлен'}"""
}],
)
return report.choices[0].message.content
Практический кейс: fintech, 3 QA на 8 разработчиков
Ситуация: QA не успевали покрывать тестами весь выходящий код. Coverage 51%, техдолг по тестам копился.
AI QA в процессе:
- При открытии PR: автоматическая генерация тест-кейсов из diff
- Генерация pytest-тестов для новых API-эндпоинтов
- Анализ упавших тестов в CI с предложением фиксов
- Еженедельный отчёт о покрытии с приоритетами
Результаты:
- Test coverage: 51% → 79% за 3 месяца
- Время написания тестов: -55%
- Обнаружение регрессий до production: +34%
- Flaky тесты выявлены и отмечены: 23 теста
Сроки
- Генератор тест-кейсов из требований: 1–2 недели
- Автогенерация pytest/Playwright тестов: 2–3 недели
- Анализатор упавших тестов + CI-интеграция: 1–2 недели
- Coverage reporting: 1 неделя
- Итого: 5–8 недель







