AI-система для тестування ПЗ (AI QA)

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
AI-система для тестування ПЗ (AI QA)
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

AI-система тестування та QA програмного забезпечення

Покриття коду тестами на 80% звучить добре, поки не дивишся на те, що саме покрито: happy path, очевидні кейси, але не граничні умови, не інтеграції між компонентами, не edge cases з неочікуваними даними. AI-система QA вирішує не проблему "немає тестів", а проблему "тести є, але вони не ловлять те, що потрібно".

Компоненти AI-системи тестування

[Аналіз коду]        [Аналіз вимог]
  AST парсинг          NLP з Jira/Confluence
       ↓                        ↓
[Движок генерації тестів]
  Unit | Integration | E2E | API
       ↓
[Пріоритизація тестів]
  Change Impact Analysis → запускати потрібні тесты, не все
       ↓
[Аналіз результатів]
  Класифікація відмов + Пропозиція root cause
       ↓
[Інтелект покриття]
  Семантичні прогалини в покритті

AI-аналіз покриття: пошук семантичних прогалин

Традиційне покриття (Istanbul, JaCoCo) рахує рядки. Проблема: 100% line coverage не означає, що протестовані всі бізнес-сценарії.

from langchain_openai import ChatOpenAI
import ast
import textwrap

class SemanticCoverageAnalyzer:
    """Аналізує семантичні прогалини в тестовому покритті"""

    ANALYSIS_PROMPT = """Проаналізуй функцію та існуючі тести.
Визнач, які бізнес-сценарії та граничні умови НЕ покриті.

Функція:
```python
{function_code}

Існуючі тести:

{existing_tests}

Визнач непокриті сценарії:

  1. Граничні значення (empty string, None, 0, max int, negative)
  2. Комбінації параметрів
  3. Сценарії помилок (exceptions, invalid input)
  4. Конкурентні доступи (якщо застосовно)
  5. Бізнес-правила в умовах

Для кожного: опиши сценарій + чому важливо + можлива помилка якщо не тестувати. Повернення JSON: {{gaps: [{{scenario, importance, potential_bug}}]}}"""

def __init__(self):
    self.llm = ChatOpenAI(model="gpt-4o", temperature=0.1)

def analyze_function_coverage(
    self,
    function_source: str,
    test_source: str
) -> list[dict]:
    result = self.llm.invoke(
        self.ANALYSIS_PROMPT.format(
            function_code=function_source,
            existing_tests=test_source
        )
    )
    import json
    return json.loads(result.content)["gaps"]

def extract_functions_from_module(self, source: str) -> list[dict]:
    """Витягує функції з Python-модуля через AST"""
    tree = ast.parse(source)
    functions = []
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
            func_source = ast.get_source_segment(source, node)
            complexity = self._calculate_cyclomatic_complexity(node)
            functions.append({
                "name": node.name,
                "source": func_source,
                "complexity": complexity,
                "line_start": node.lineno
            })
    return sorted(functions, key=lambda x: x["complexity"], reverse=True)

def _calculate_cyclomatic_complexity(self, node) -> int:
    """Цикломатична складність — приоритет для тестування"""
    complexity = 1
    for child in ast.walk(node):
        if isinstance(child, (ast.If, ast.While, ast.For, ast.ExceptHandler,
                               ast.With, ast.Assert)):
            complexity += 1
        elif isinstance(child, ast.BoolOp):
            complexity += len(child.values) - 1
    return complexity

### Генератор тестів з мутаційним тестуванням

```python
class AITestGenerator:
    UNIT_TEST_PROMPT = """Генеруй pytest unit-тести для функції.

Функція:
{function_code}

Непокриті сценарії (сфокусуйся на них):
{gaps}

Вимоги:
- Використовуй pytest + pytest-mock
- Параметризуй через @pytest.mark.parametrize де застосовно
- Для кожного тесту: Arrange-Act-Assert
- Тести на граничні значення
- Тесті на помилкові вхідні дані
- Mock для зовнішніх залежностей

Повернення тільки коду, без пояснень."""

    async def generate_unit_tests(
        self,
        function_source: str,
        gaps: list[dict]
    ) -> str:
        gaps_text = "\n".join([
            f"- {g['scenario']}: {g['importance']}"
            for g in gaps[:5]  # топ-5 за важливістю
        ])

        result = await self.llm.ainvoke(
            self.UNIT_TEST_PROMPT.format(
                function_code=function_source,
                gaps=gaps_text
            )
        )
        return result.content

    async def run_mutation_testing(self, source_file: str, test_file: str) -> dict:
        """Запускає мутаційне тестування через mutmut"""
        import subprocess
        result = subprocess.run(
            ["mutmut", "run", f"--paths-to-mutate={source_file}",
             f"--tests-dir={test_file}"],
            capture_output=True, text=True
        )

        # Аналізуємо пережилих мутантів (тести не спіймали зміну)
        survived = self._parse_survived_mutants(result.stdout)
        if survived:
            additional_tests = await self._generate_for_mutants(survived, source_file)
            return {"survived_count": len(survived), "additional_tests": additional_tests}

        return {"survived_count": 0, "mutation_score": "100%"}

Інтеграція в CI/CD

# .github/workflows/ai-qa.yml
name: AI QA Analysis

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  ai-test-analysis:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # потрібен для diff

      - name: Analyze changed files
        run: |
          git diff origin/main...HEAD --name-only --diff-filter=AM | \
            grep "\.py$" > changed_files.txt

      - name: Run AI coverage analysis
        run: |
          python qa_system/analyze_coverage.py \
            --changed-files changed_files.txt \
            --generate-missing-tests \
            --output coverage_report.json

      - name: Comment PR with AI findings
        uses: actions/github-script@v7
        with:
          script: |
            const report = require('./coverage_report.json')
            const comment = formatReport(report)
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              body: comment
            })

Кейс: backend сервіс на Python (FastAPI), 45 000 рядків коду, 380 тестів. Coverage: 74%. AI-аналіз виявив 89 семантичних прогалин (не рядкових — сценарних), з яких 34 позначені як високопріоритетні. Генеровано 67 додаткових тестів. При прогоні: 8 з 67 тестів впали — знайшли реальні баги в обробці граничних умов (None в агрегації, від'ємні кількості в замовленні, порожній список при сортуванні).

Строки

  • Аналіз покриття + генерація unit-тестів: 3–4 тижні
  • Повна QA-система з CI/CD інтеграцією: 8–10 тижнів
  • Мутаційне тестування та E2E: +2–3 тижні