Skip to content
IRC-CodingIRC-Coding
Regression TestingТестирование регрессииАвтоматизация тестовКачество ПОUnit TestsIntegration TestsE2E Tests

Regression Testing: Защита функций от ошибок

Изучите Regression Testing: цели, стратегии, автоматизация и лучшие практики для защиты существующего функционала.

S

schutzgeist

15 min read
Regression Testing: Защита функций от ошибок

Регрессионные тесты

Регрессионные тесты гарантируют, что новые изменения, исправления багов или рефакторинг не сломают существующий функционал. Это незаменимая часть любой системы качества, особенно в agile-командах с короткими циклами релиза. Без регрессионных тестов страх перед изменениями растёт, а код деградирует.

In a Nutshell

  • Регрессионные тесты проверяют, что старые функции продолжают работать.
  • Они запускаются после каждого значимого изменения.
  • Автоматизация критична для масштабируемости регрессионного тестирования.
  • Unit, интеграционные и E2E тесты могут служить регрессионными тестами.
  • Хорошая стратегия регрессионного тестирования приоритизирует критические пути.

Краткое описание

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

Регрессионные тесты по сути не являются отдельным видом тестирования, а скорее стратегией: вы решаете, какие существующие тесты нужно перезапустить после изменения. Выбор может быть полным, основанным на риске или на анализе влияния.

Когда запускаются регрессионные тесты?

Регрессионные тесты применяются всякий раз, когда меняется код или окружение приложения. Основные триггеры:

  • После изменений кода или исправления ошибок: Любое изменение может иметь побочные эффекты. Регрессионные тесты гарантируют, что существующий функционал не будет случайно сломан.
  • После рефакторинга: При переструктурировании кода поведение должно остаться неизменным. Регрессионные тесты подтверждают, что никаких изменений в поведении не произошло.
  • После обновления зависимостей: Новые версии библиотек или фреймворков могут содержать несовместимые изменения. Регрессионные тесты проверяют, что система работает корректно.
  • После слияния в основную ветку: Перед интеграцией кода в main ветку запускаются регрессионные тесты для раннего обнаружения конфликтов и побочных эффектов.
  • Перед релизом: Перед выпуском полный набор регрессионных тестов подтверждает общее качество.
  • При регулярных ночных прогонах: Автоматизированные ночные запуски выявляют регрессии, пропущенные в течение дня.

Виды регрессионных тестов

Unit-тесты регрессии

Unit-тесты регрессии проверяют отдельные функции или классы после изменений. Они быстрые и часто запускаются, идеально на каждом commit. Это первая линия защиты от регрессий, потому что они работают изолированно и выполняются за миллисекунды. Типичный пример: функция расчёта скидки изменена. Unit-тесты проверяют все предыдущие правила скидок и гарантируют, что результаты неизменны.

Интеграционные тесты регрессии

Интеграционные тесты регрессии проверяют взаимодействие между модулями, которые могут быть затронуты изменением. Они медленнее unit-тестов, но важны для обнаружения побочных эффектов на границах модулей. Пример: после изменения логики расчёта цены тестируется, продолжает ли корзина, платёжная система и генерация счетов работать корректно вместе.

E2E-тесты регрессии

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

Стратегии регрессионного тестирования

Полная регрессия

Запускаются все существующие тесты. Это самый безопасный вариант, но при больших наборах тестов очень затратно по времени. Типично используется только перед релизами или в ночных прогонах.

Регрессия на основе риска

Запускаются только тесты, покрывающие критические или часто используемые функции. Эта стратегия требует приоритизации тестов по важности и частоте использования.

Анализ влияния тестов

Анализ влияния определяет, какие части кода затронуты изменением, и запускает только тесты, покрывающие эти области. Это требует инструментов, способных анализировать зависимости в коде.

Практический пример

Следующий пример показывает, как регрессионные тесты применяются на практике. Он выбран потому, что объединяет все три уровня тестирования и демонстрирует, как целевое изменение приводит к систематической стратегии тестирования.

Разработчик изменяет логику скидок в checkout.

Регрессионные тесты:
- Unit-тесты для всех правил скидок
- Интеграционные тесты для корзины и расчёта цены
- E2E-тест для полного flow checkout
- Исследовательское тестирование старых функций скидок

Почему эти тесты?

  • Unit-тесты: Логика скидок это изолируемая функция. Unit-тесты проверяют каждое правило скидки отдельно и гарантируют, что расчёты для всех предыдущих случаев остаются корректными.
  • Интеграционные тесты: Корзина и расчёт цены напрямую зависят от логики скидок. Интеграционные тесты проверяют, что общий расчёт цены с новыми правилами скидок остаётся корректным.
  • E2E-тест: Полный flow checkout это самый критический бизнес-процесс. E2E-тест гарантирует, что пользователь может завершить покупку без ошибок.
  • Исследовательское тестирование: Автоматизированные тесты покрывают известные случаи. Исследовательское тестирование находит неожиданные побочные эффекты, которые автотесты не охватывают.

Преимущества и недостатки

ПреимуществаНедостатки
Защита от регрессионных ошибокРастущий объём тестов при добавлении функций
Уверенность в рефакторинге и изменениях кодаДлительное время выполнения без правильной стратегии
Безопаснее и частотнее релизыЗатраты на поддержку тестов
Раннее обнаружение побочных эффектовРучное регрессионное тестирование дорого и медленно
Живая документация ожидаемого поведенияFalse positives подрывают доверие к наборам тестов
Объективная оценка качества перед релизомНачальные затраты на автоматизацию

Best Practices

  • Автоматизируйте: Ручное регрессионное тестирование не масштабируется при частых изменениях.
  • Приоритизируйте: Не все тесты одинаково важны. Сначала критические пути.
  • Поддерживайте тесты: Тесты должны легко адаптироваться при изменениях кода.
  • Держите тесты быстрыми: Медленные наборы тестов замедляют разработку. Параллелизация и целевой выбор помогают.
  • Интегрируйте в CI/CD: Регрессионные тесты должны запускаться автоматически при каждом commit или merge.
  • Избегайте false positives: Нестабильные тесты подрывают доверие к набору.
  • Используйте анализ влияния: Запускайте только затронутые тесты, чтобы сэкономить время.

Подробный практический пример: FastAPI + NiceGui проект с Docker и CI/CD

Контекст проекта

Проект состоит из:

  • FastAPI как бэкенд — предоставляет API-эндпойнты для инструментов преобразования текста (например, Markdown→HTML, JSON→YAML, Base64-кодирование/декодирование, статистика текста)
  • NiceGui как фронтенд — веб-интерфейс, который вызывает API-эндпойнты и отображает результаты
  • Docker — инструмент работает локально при разработке и на сервере в контейнерах Docker
  • Дополнительные модули — например, pydantic для валидации, httpx для асинхронных HTTP-запросов, python-slugify для генерации URL-слагов

Проблема вибекодирования: генерация кода на основе AI часто случайно изменяет другие файлы, удаляет библиотеки или меняет импорты. Функция, которая работала вчера, вдруг ломается, а разработчик это не замечает, потому что изменение произошло совсем в другом месте.

Структура проекта

my-text-tools/
├── app/
│   ├── __init__.py
│   ├── main.py              # FastAPI-app, регистрирует роутеры
│   ├── routers/
│   │   ├── __init__.py
│   │   ├── markdown.py      # /api/markdown → HTML
│   │   ├── json_yaml.py     # /api/json-to-yaml, /api/yaml-to-json
│   │   ├── base64.py        # /api/base64/encode, /api/base64/decode
│   │   └── stats.py         # /api/stats (слова, символы, строки)
│   ├── models/
│   │   ├── __init__.py
│   │   └── schemas.py       # Pydantic-модели для Request/Response
│   ├── services/
│   │   ├── __init__.py
│   │   ├── converter.py     # Ядро логики: функции конвертирования
│   │   └── slugify.py       # Генерация слагов
│   └── ui/
│       ├── __init__.py
│       └── nicegui_app.py   # NiceGui-фронтенд, вызывает API
├── tests/
│   ├── __init__.py
│   ├── conftest.py           # pytest-фиксчуры (тестовый клиент, моки)
│   ├── unit/
│   │   ├── test_converter.py
│   │   ├── test_slugify.py
│   │   └── test_models.py
│   ├── integration/
│   │   ├── test_markdown_api.py
│   │   ├── test_json_yaml_api.py
│   │   ├── test_base64_api.py
│   │   └── test_stats_api.py
│   └── e2e/
│       └── test_ui_flows.py  # Тесты NiceGui-интерфейса через Playwright
├── Dockerfile
├── docker-compose.yml
├── docker-compose.test.yml   # Окружение для тестирования с изолированной БД
├── requirements.txt
├── requirements-dev.txt      # pytest, pytest-asyncio, httpx, playwright
├── .github/
│   └── workflows/
│       ├── ci.yml            # Lint + Unit + Integration при каждом push
│       └── nightly.yml       # Полная регрессионная сьюта ночью
├── Makefile                  # make test, make test-unit, make test-e2e
└── pytest.ini

Шаг 1: Unit-регрессионные тесты с pytest

Unit-тесты проверяют ядро логики изолированно, без базы данных, без сети, без интерфейса.

# tests/unit/test_converter.py
import pytest
from app.services.converter import (
    markdown_to_html,
    json_to_yaml,
    yaml_to_json,
    base64_encode,
    base64_decode,
    text_statistics,
)

class TestMarkdownToHtml:
    """Регрессионные тесты для преобразования Markdown."""

    def test_simple_heading(self):
        assert markdown_to_html("# Titel") == "<h1>Titel</h1>"

    def test_bold_text(self):
        assert markdown_to_html("**fett**") == "<strong>fett</strong>"

    def test_code_block(self):
        md = "```python\nprint('hello')\n```"
        result = markdown_to_html(md)
        assert "<code>" in result
        assert "print('hello')" in result

    def test_empty_input(self):
        assert markdown_to_html("") == ""

    def test_nested_lists(self):
        md = "- Item 1\n  - Subitem 1.1"
        result = markdown_to_html(md)
        assert "<ul>" in result
        assert "<li>Item 1" in result

    # Регрессия: вибекодирование удаляет библиотеку → ImportError
    def test_module_imports_successfully(self):
        """Убедиться, что конвертер остаётся импортируемым.
        Если вибекодирование, скажем, удалит 'markdown' из requirements.txt,
        этот тест упадёт."""
        from app.services import converter
        assert hasattr(converter, 'markdown_to_html')


class TestJsonYamlConversion:
    """Регрессионные тесты для преобразования JSON↔YAML."""

    def test_json_to_yaml_basic(self):
        json_input = '{"name": "test", "value": 42}'
        result = json_to_yaml(json_input)
        assert "name: test" in result
        assert "value: 42" in result

    def test_roundtrip_json_yaml_json(self):
        """JSON → YAML → JSON должны быть идентичны."""
        import json
        original = {"name": "test", "list": [1, 2, 3]}
        json_str = json.dumps(original)
        yaml_str = json_to_yaml(json_str)
        back = yaml_to_json(yaml_str)
        assert json.loads(back) == original

    def test_nested_structures(self):
        json_input = '{"outer": {"inner": {"deep": true}}}'
        result = json_to_yaml(json_input)
        assert "inner:" in result
        assert "deep: true" in result


class TestBase64:
    """Регрессионные тесты для Base64-кодирования/декодирования."""

    def test_encode_decode_roundtrip(self):
        original = "Hello, World!"
        encoded = base64_encode(original)
        decoded = base64_decode(encoded)
        assert decoded == original

    def test_encode_empty_string(self):
        assert base64_encode("") == ""

    def test_decode_invalid_input_raises(self):
        with pytest.raises(Exception):
            base64_decode("!!!invalid_base64!!!")


class TestTextStatistics:
    """Регрессионные тесты для статистики текста."""

    def test_word_count(self):
        stats = text_statistics("hello world foo")
        assert stats["words"] == 3

    def test_empty_text(self):
        stats = text_statistics("")
        assert stats["words"] == 0
        assert stats["characters"] == 0
        assert stats["lines"] == 0

    def test_multiline(self):
        stats = text_statistics("line1\nline2\nline3")
        assert stats["lines"] == 3
# tests/unit/test_slugify.py
from app.services.slugify import slugify

class TestSlugify:
    """Регрессия: если python-slugify удалится из requirements,
    этот тест упадёт, защитив от непреднамеренной потери библиотеки."""

    def test_basic_slug(self):
        assert slugify("Hello World") == "hello-world"

    def test_german_umlauts(self):
        assert slugify("Übergröße") == "ubergrose"

    def test_special_characters(self):
        assert slugify("Python 3.12!@#") == "python-312"

    def test_empty_string(self):
        assert slugify("") == ""

Шаг 2: Интеграционные регрессионные тесты с pytest + httpx

Интеграционные тесты проверяют API-эндпойнты через TestClient FastAPI.

# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from app.main import app

@pytest.fixture
def client():
    """TestClient FastAPI для интеграционных тестов."""
    return TestClient(app)

@pytest.fixture
def sample_markdown():
    return "# Test\n\n**Bold** text with `code`."
# tests/integration/test_markdown_api.py
class TestMarkdownAPI:
    """Регрессионные тесты для эндпойнта /api/markdown."""

    def test_markdown_to_html_success(self, client, sample_markdown):
        response = client.post("/api/markdown", json={"text": sample_markdown})
        assert response.status_code == 200
        data = response.json()
        assert "<h1>Test</h1>" in data["html"]
        assert "<strong>Bold</strong>" in data["html"]

    def test_markdown_empty_input(self, client):
        response = client.post("/api/markdown", json={"text": ""})
        assert response.status_code == 200
        assert response.json()["html"] == ""

    def test_markdown_missing_field(self, client):
        """Регрессия: валидация Pydantic должна оставаться активной.
        Если вибекодирование изменит модель, этот тест упадёт."""
        response = client.post("/api/markdown", json={})
        assert response.status_code == 422  # Validation Error

    def test_markdown_invalid_json(self, client):
        response = client.post("/api/markdown", data="not json")
        assert response.status_code == 422
# tests/integration/test_stats_api.py
class TestStatsAPI:
    """Регрессионные тесты для /api/stats."""

    def test_stats_basic(self, client):
        response = client.post("/api/stats", json={"text": "hello world"})
        assert response.status_code == 200
        data = response.json()
        assert data["words"] == 2
        assert data["characters"] == 11

    def test_stats_empty(self, client):
        response = client.post("/api/stats", json={"text": ""})
        assert response.status_code == 200
        assert response.json()["words"] == 0

    # Регрессия: проверяет, что эндпойнт вообще существует.
    # Если вибекодирование удалит роутер, тест упадёт.
    def test_stats_endpoint_exists(self, client):
        response = client.post("/api/stats", json={"text": "test"})
        assert response.status_code != 404

Шаг 3: E2E-регрессионные тесты с Playwright

E2E-тесты проверяют интерфейс NiceGui через реальный браузер.

# tests/e2e/test_ui_flows.py
"""E2E-регрессионные тесты для интерфейса NiceGui.
Требует, чтобы приложение было запущено (docker-compose up -d)."""
import pytest
from playwright.sync_api import Page, expect

BASE_URL = "http://localhost:8080"

class TestMarkdownConverterUI:
    """Проверяет, работает ли преобразование Markdown через интерфейс."""

    def test_markdown_input_and_output(self, page: Page):
        page.goto(BASE_URL)
        page.fill("[data-testid='markdown-input']", "# Hallo Welt")
        page.click("[data-testid='convert-button']")
        output = page.locator("[data-testid='markdown-output']")
        expect(output).to_contain_text("Hallo Welt")
        expect(output).to_contain_text("<h1>")

    def test_clear_button(self, page: Page):
        page.goto(BASE_URL)
        page.fill("[data-testid='markdown-input']", "# Test")
        page.click("[data-testid='clear-button']")
        assert page.locator("[data-testid='markdown-input']").input_value() == ""

class TestNavigationRegression:
    """Гарантирует, что все вкладки интерфейса остаются доступны.
    Если Vibecoding удалит вкладку, этот тест упадёт."""

    @pytest.mark.parametrize("tab_name", [
        "Markdown", "JSON/YAML", "Base64", "Statistики"
    ])
    def test_tab_accessible(self, page: Page, tab_name):
        page.goto(BASE_URL)
        page.click(f"text={tab_name}")
        # Проверяет, что содержимое вкладки видимо
        content = page.locator("[data-testid='tab-content']")
        expect(content).to_be_visible()

Шаг 4: Docker-тестовая конфигурация

# Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Запускаем NiceGui + FastAPI
EXPOSE 8080
CMD ["python", "-m", "app.main"]
# docker-compose.test.yml
# Изолированная тестовая среда — без доступа к боевым данным
version: "3.9"
services:
  app-test:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8081:8080"  # Другой порт, чем в боевой среде
    environment:
      - TESTING=true
      - LOG_LEVEL=DEBUG
    command: >
      bash -c "pip install -r requirements-dev.txt &&
               pytest tests/unit tests/integration -v --tb=short &&
               pytest tests/e2e -v --tb=short"

Шаг 5: CI/CD-пайплайн с GitHub Actions

# .github/workflows/ci.yml
name: CI Regression Tests
on:
  push:
    branches: [main, dev]
  pull_request:
    branches: [main]

jobs:
  unit-and-integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: pytest tests/unit tests/integration -v --tb=short --junitxml=results.xml
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: results.xml

  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: playwright install --with-deps chromium
      - name: Start app in background
        run: |
          python -m app.main &
          sleep 5
      - run: pytest tests/e2e -v --tb=short

  docker-build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: docker compose -f docker-compose.test.yml up --exit-code-from app-test
# .github/workflows/nightly.yml
name: Nightly Full Regression
on:
  schedule:
    - cron: "0 2 * * *"  # Каждую ночь в 02:00

jobs:
  full-regression:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: playwright install --with-deps chromium
      - name: Start app
        run: python -m app.main & sleep 5
      - name: Full regression suite
        run: pytest -v --tb=long --junitxml=nightly-results.xml
      - name: Notify on failure
        if: failure()
        run: |
          echo "::error::Nightly regression failed — check logs"

Шаг 6: Makefile для локального запуска

# Makefile
.PHONY: test test-unit test-integration test-e2e test-docker test-watch

test: test-unit test-integration
	@echo "✅ Unit + Integration Tests прошли успешно"

test-unit:
	pytest tests/unit -v --tb=short

test-integration:
	pytest tests/integration -v --tb=short

test-e2e:
	pytest tests/e2e -v --tb=short

test-docker:
	docker compose -f docker-compose.test.yml up --exit-code-from app-test

test-watch:
	ptw -- -v --tb=short tests/

test-coverage:
	pytest --cov=app --cov-report=html tests/unit tests/integration
	@echo "📊 Coverage Report: htmlcov/index.html"

Шаг 7: Документирование тестов

Каждый тестовый файл должен быть задокументирован. Рекомендуемая структура:

docs/
├── testing.md              # Тестовая стратегия и руководство
├── test-cases.md           # Список всех тестовых случаев с описанием
└── troubleshooting.md      # Известные проблемы и их решения

docs/testing.md должен содержать:

  1. Тестовая стратегия — какие тесты когда запускаются (Unit при коммите, Integration при PR, E2E ночью)
  2. Запускmake test, make test-unit, make test-docker
  3. Интеграция с CI/CD — какие워ークфлоу существуют и когда они срабатывают
  4. Добавление новых тестов — соглашения по именованию файлов, фиксчурам, ассертам
  5. Покрытие тестамиmake test-coverage и целевое покрытие (например, ≥ 80%)
  6. Решение проблем — частые ошибки и способы их исправления

Шаг 8: Рекомендации для Vibecoding

При использовании Vibecoding (генерация кода с помощью AI) регрессии часто возникают из-за:

  • Удалённых импортов — AI удаляет import в одном файле, который требуется другому файлу
  • Изменённых сигнатур функций — параметры переименовываются или удаляются
  • Удалённых вспомогательных функций — AI считает функцию “неиспользуемой” и удаляет её
  • Изменённых Pydantic-моделей — поля удаляются или переименовываются, валидация API меняется

Защитные меры:

  1. Import-Guard-тесты — каждый файл тестов начинается с теста на импортирование всех нужных модулей:

    def test_module_imports():
        """Регрессия: проверяет, что все модули остаются импортируемы."""
        import app.services.converter
        import app.services.slugify
        import app.routers.markdown
        import app.routers.stats
  2. API-контрактные тесты — проверяют, что эндпоинты возвращают ожидаемые поля:

    def test_stats_response_schema(client):
        """Регрессия: если Pydantic-модель изменится, этот тест упадёт."""
        response = client.post("/api/stats", json={"text": "test"})
        data = response.json()
        assert "words" in data
        assert "characters" in data
        assert "lines" in data
  3. Проверка зависимостей — тест, который парсит requirements.txt и проверяет, что все импортируемые пакеты там перечислены:

    def test_all_imports_in_requirements():
        """Регрессия: если Vibecoding удалит импорт,
        но код будет на него ссылаться, или наоборот."""
        # Парсим requirements.txt
        with open("requirements.txt") as f:
            requirements = {
                line.split("==")[0].split(">=")[0].strip().lower()
                for line in f if line.strip() and not line.startswith("#")
            }
        # Проверяем критические пакеты
        assert "fastapi" in requirements
        assert "nicegui" in requirements
        assert "pydantic" in requirements
        assert "httpx" in requirements
        assert "python-slugify" in requirements
  4. Pre-commit hook — запускает Unit-тесты перед каждым коммитом:

    # .git/hooks/pre-commit
    #!/bin/bash
    pytest tests/unit -v --tb=short || exit 1
  5. Проверка git diff — после каждой сессии Vibecoding смотрим git diff:

    git diff --stat          # Какие файлы изменились?
    git diff requirements.txt # Пакеты были удалены?
    git diff app/services/    # Изменилась ли основная логика?

Итоговая таблица: пирамида тестов для этого проекта

УровеньИнструментКогдаВремяКоличество
UnitpytestПри каждом коммите< 5 s30–50
Integrationpytest + TestClientПри каждом PR< 30 s15–25
E2EPlaywrightНочные прогоны + перед релизом2–5 min5–10
Dockerdocker-compose.testПри каждом PR1–2 min1 Suite

Правило: Когда изменение затрагивает функциональность, unit-тесты и интеграционные тесты этого модуля должны пройти зелёными перед коммитом.

Основные инструменты

  • JUnit / pytest / Jest: Фреймворки для юнит-тестов на регрессию.
  • Selenium / Cypress / Playwright: Инструменты для E2E-тестов на регрессию.
  • Postman / REST Assured: Тестирование API на регрессию.
  • TestNG / NUnit: Фреймворки с расширенными функциями управления тестами.
  • Jenkins / GitHub Actions / GitLab CI: CI/CD-конвейеры для автоматизации регрессионного тестирования.

Ключевые понятия

  • Регрессионный тест: тест, проверяющий, что существующие функции продолжают работать после изменений в коде.
  • Регрессионный дефект: ошибка, возникшая в ранее работавшей части системы из-за нового изменения.
  • Триггеры: изменения кода, исправления багов, рефакторинг, обновления зависимостей, слияния веток, релизы.
  • Уровни тестирования: unit, интеграционные и E2E-тесты используются как регрессионные.
  • Стратегии: полная регрессия, рискованная регрессия, анализ влияния тестов.
  • Автоматизация: критична для масштабируемого и повторяемого регрессионного тестирования.
  • Smoke Test: минимальный набор проверок, убеждающих в базовой работоспособности системы.
  • Sanity Test: целевая проверка, валидирующая одно небольшое изменение.
  • Nightly Build: автоматический ночной прогон тестов для раннего выявления проблем.
  • CI/CD-интеграция: регрессионные тесты запускаются автоматически при каждом коммите или слиянии.
  • Поддержка: тесты должны обновляться при изменении кода.
  • False Positives: нестабильные тесты подрывают доверие к набору.

Основные источники

  1. https://www.guru99.com/regression-testing.html
  2. https://www.atlassian.com/continuous-delivery/software-testing/regression-testing
  3. https://en.wikipedia.org/wiki/Regression_testing

Часто задаваемые вопросы

Что такое регрессионный тест?

Регрессионный тест проверяет, что существующие функции продолжают работать правильно после изменений кода. Он предотвращает ломку существующего функционала из-за новых фич или исправлений.

Когда проводят регрессионные тесты?

После изменений кода, исправления багов, рефакторинга, обновления зависимостей, слияния в основную ветку, перед релизами и в ночных прогонах.

Что такое регрессионный дефект?

Регрессионный дефект возникает в ранее работавшей части системы из-за нового изменения. Его часто сложно найти, потому что изменение было сделано в другом месте.

Почему автоматизируют регрессионные тесты?

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

На каких уровнях запускаются регрессионные тесты?

На всех: unit-тесты проверяют изолированные функции, интеграционные тесты проверяют взаимодействие компонентов, E2E-тесты валидируют полные пользовательские сценарии.

Что такое стратегия регрессионного тестирования?

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

Нужно ли всегда повторять все тесты?

Нет. При большом наборе тестов это займёт слишком много времени. Вместо этого нужно выбирать тесты на основе риска или проводить анализ влияния изменений.

Что такое Smoke Test?

Smoke Test это минимальный набор проверок, убеждающих в базовой работоспособности системы и доступности ключевых функций.

Что такое Sanity Test?

Sanity Test это целевая проверка, валидирующая одно небольшое изменение. Она быстрее, чем полный регрессионный набор.

Как выбирают регрессионные тесты?

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

Какое преимущество у регрессионных тестов?

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

Какой минус у ручного регрессионного тестирования?

Оно дорого, медленно и подвержено ошибкам. При частых изменениях оно не масштабируется и часто приводит к неполной покрытости.

Как часто должны запускаться регрессионные тесты?

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

Что такое анализ влияния тестов?

Анализ влияния определяет, какие части кода затронуты изменением, и запускает только тесты, покрывающие эти области.

Могут ли регрессионные тесты предотвратить появление багов?

Они напрямую не предотвращают баги, но быстро находят побочные ошибки, возникшие из-за изменений, до попадания в продакшн.

Что такое False Positive при регрессионном тестировании?

False Positive это тест, который падает, хотя код работает корректно. Типичные причины: нестабильные тесты, проблемы с синхронизацией, ошибки в тестовых данных.

Чем отличается Smoke Test от Sanity Test?

Smoke Test проверяет систему широко, но поверхностно. Sanity Test проверяет конкретное изменение углублённо. Smoke Tests шире, Sanity Tests глубже.

Какие инструменты подходят для регрессионного тестирования?

JUnit, pytest и Jest для unit-тестов. Selenium, Cypress и Playwright для E2E. Postman для API-тестов. Jenkins и GitHub Actions для CI/CD-интеграции.

Что такое Nightly Build?

Nightly Build это автоматический ночной прогон сборки и тестов для выявления регрессий, пропущенных в течение дня.

Чем отличается регрессионный тест от перетестирования?

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

Продолжаем путь обучения тестированию

Следующая статья в этом направлении посвящена приёмочному тестированию — как приёмочные тесты гарантируют выполнение требований.

Назад к блогу
Share:

Похожие статьи