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}
Критерії прийому:
{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 для подібних тест-кейсів
- Використовуй наявні 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)}, з них автоматизовано: {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-endpoint'ів
- Аналіз невдалих тестів у CI з пропозицією фіксів
- Щотижневий звіт про покриття з пріоритетами
Результати:
- Тестове покриття: 51% → 79% за 3 місяці
- Час написання тестів: -55%
- Виявлення регресій до production: +34%
- Flaky тести виявлені та позначені: 23 тести
Терміни
- Генератор тест-кейсів із вимог: 1–2 тижні
- Автогенерація pytest/Playwright тестів: 2–3 тижні
- Аналізатор невдалих тестів + CI-інтеграція: 1–2 тижні
- Coverage reporting: 1 тиждень
- Всього: 5–8 тижнів







