✅ Решения заданий и ответы на вопросы самопроверки

Теоретические ответы

Ответ 1. Что такое Auto QA?

Auto QA — автоматизация тестирования: использование инструментов и скриптов для выполнения тестов с минимальным участием человека. Отличие от ручного тестирования: тесты запускаются автоматически при каждом коммите (CI/CD), выполняются быстро и воспроизводимо без участия человека.

Ответ 2. Пирамида тестирования

  • Unit Tests — проверяют отдельные функции/методы в изоляции. Быстрые и дешёвые.
  • Integration Tests — проверяют взаимодействие между компонентами. Медленнее и дороже.
  • E2E Tests — проверяют систему целиком. Самые медленные и дорогие.

Unit-тестов больше, потому что они дёшевы, быстры и покрывают большую часть логики. E2E — дорогие и медленные, поэтому их используют только для критических сценариев.

Ответ 3. Тестирование ПО

Тестирование — не просто поиск багов, а проверка соответствия реального поведения программы ожидаемому. «Проверка ожиданий» означает: вы должны знать, что программа должна делать, и проверить, делает ли она именно это.

Ответ 4. Соглашения pytest

  • Файлы: имена начинаются с test_ или заканчиваются на _test.py.
  • Функции: имена начинаются с test_.

Если нарушить это правило — pytest не найдёт тест и не запустит его без ошибки (тест просто будет проигнорирован).

Ответ 5. Фикстура

@pytest.fixture позволяет создать ресурс один раз и передавать его в несколько тестов. Если создавать Calculator() в каждом тесте — код дублируется. С фикстурой — логика инициализации в одном месте, легко изменить.

Ответ 6. skip vs xfail

@pytest.mark.skip — тест полностью исключается из выполнения (ни запускается, ни проверяется). Используется, когда функциональность не готова. @pytest.mark.xfail — тест запускается, но ожидается его провал. Используется, когда известен баг или метод в разработке. Если xfail-тест вдруг пройдёт — pytest пометит его как xpass.

Ответ 7. Пользовательские маркеры

Регистрация в pytest.ini:

[pytest]
markers =
    positive_test: Тесты для позитивных сценариев

Без регистрации pytest выдаст предупреждение PytestUnknownMarkWarning. Тесты всё равно запустятся, но в строгом режиме (--strict-markers) будет ошибка.

Ответ 8. pytest -k vs pytest -m

pytest -k "sum" — фильтрует по подстроке в имени теста. pytest -m positive_test — фильтрует по маркеру, заданному через декоратор. -k гибче для быстрого поиска, -m — для организованных категорий.

Решения практических заданий

Задание 1: Параметризация sub

# test_calculator.py
import pytest
from calculator import Calculator

@pytest.fixture
def calculator():
    return Calculator()

@pytest.mark.parametrize('a, b, result', [
    (10, 3, 7),
    (-5, -3, -2),
    (0, 5, -5)
])
def test_sub(a, b, result, calculator):
    assert calculator.sub(a, b) == result

Задание 2: Маркировка negative_test

# pytest.ini
[pytest]
markers =
    negative_test: Тесты для негативных сценариев
# test_calculator.py
@pytest.mark.negative_test
def test_division_by_zero(calculator):
    with pytest.raises(ArithmeticError, match="На ноль делить нельзя"):
        calculator.div(10, 0)
# Запуск
pytest -m negative_test

Задание 3: xfail

@pytest.mark.xfail(reason="Умышленная ошибка для демонстрации xfail")
def test_sum_wrong_expectation():
    calculator = Calculator()
    assert calculator.sum(1, 1) == 3  # Ожидаем 3, получим 2 -> xfail

Вывод pytest: XFAIL test_calculator.py::test_sum_wrong_expectation — тест провалился, как и ожидалось. Это нормальный статус, не ошибка.

Задание 4: SimpleMath с параметризацией

# test_simple_math_param.py
import pytest
from simple_math import SimpleMath

@pytest.fixture
def math():
    return SimpleMath()

@pytest.mark.parametrize('n, result', [
    (2, 4),
    (-3, 9),
    (0, 0),
    (10, 100),
    (-1, 1)
])
def test_square(n, result, math):
    assert math.square(n) == result

@pytest.mark.parametrize('n, result', [
    (3, 27),
    (-2, -8),
    (0, 0),
    (1, 1),
    (-1, -1)
])
def test_cube(n, result, math):
    assert math.cube(n) == result