Раздел 01 — Автоматизация тестирования

Какие проверки отдать машине и как выглядит набор автотестов, который реально помогает

Прогресс курса Раздел 1 из 12

Что вы освоите в этом разделе

4 академических часа: 2 теории, 2 практики. Нужны Python 3.10+ и «Задачник» из курса ручного тестирования — установка в приложении А1 того курса. Python и VS Code подробно ставим в разделе 02; в этом разделе достаточно запустить готовый набор по инструкции ниже.
01

Что такое автотест

Автотест — программа, которая выполняет проверку и сама сравнивает фактический результат с ожидаемым. Ручной тест-кейс говорит человеку: «откройте, введите, сравните». Автотест делает то же самое кодом и в конце отвечает одним словом: прошёл или упал.

Ручная проверкаАвтотест
Кто сравниваетЧеловек, глазамиПрограмма, строкой assert
ПовторКаждый раз заново, минуты и часыОдной командой, секунды
Замечает неожиданноеДа: «а почему кнопка серая?»Нет: проверяет только то, что написано
СтоимостьДёшево один раз, дорого сто разДорого написать и поддерживать, дёшево повторять
Устаёт и пропускаетДа, особенно на десятом повтореНет, но «слепнет», если ожидание записано неверно

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

02

Когда автоматизация окупается

Автотест окупается, когда суммарное время ручных повторов больше, чем время на его написание и поддержку. Грубая оценка: проверку, которую повторяют реже трёх-четырёх раз, автоматизировать обычно невыгодно.

Автоматизировать в первую очередьОставить ручным
Регресс: проверки, которые повторяют перед каждым выпускомРазовая проверка новой функции, которая ещё меняется каждый день
Много вариантов данных: границы, классы, комбинацииУдобство, внешний вид, «понятно ли пользователю»
API: быстро, стабильно, не зависит от вёрсткиИсследовательское тестирование
Расчёты, правила, проверки полей — модульными тестамиПроверки, для которых нужен живой человек: печать, звонок, бумажный документ
Smoke новой сборки: «главное вообще работает?»Редкие сценарии, где тест дороже, чем вероятный ущерб

Пример расчёта. Регресс «Задачника» вручную — 2 часа. Выпуски — раз в неделю. Набор автотестов на те же проверки пишется за 16 часов и требует около 30 минут поддержки в неделю. Ручной регресс за 10 недель — 20 часов, автоматизированный — 16 + 5 = 21 час. Окупаемость — примерно на одиннадцатой неделе; дальше каждая неделя экономит полтора часа и даёт прогон за минуту вместо двух часов.

Главная статья расходов автоматизации — не написание, а поддержка. Тест, который падает «просто так» раз в неделю, команда быстро перестаёт смотреть, и набор теряет смысл. Поэтому в курсе столько места уделено стабильности (раздел 09).
03

Пирамида тестов

Пирамида тестов — правило о пропорциях набора: внизу много быстрых и дешёвых тестов, наверху — немного медленных и дорогих.

УровеньЧто проверяетСкорость одного тестаДоля в набореРаздел курса
UI (сквозные)Сценарий пользователя в браузере: вход, создание задачи, фильтрСекундыНемного: главные сценарии08–09
API (интеграционные)Запросы к серверу и ответы: коды, тело, права доступаДесятки миллисекундСредняя часть06–07
МодульныеОдна функция в изоляции: проверка поля, расчёт срокаМиллисекундыОснова: большинство03–05

Почему не наоборот. UI-тест проходит через всё приложение сразу: браузер, вёрстку, сервер, базу. Он медленный, а когда падает, непонятно, где причина. Модульный тест падает ровно на той функции, которая сломана. Если проверку можно сделать уровнем ниже — её делают ниже. Проверку «название из 101 символа отклоняется» не нужно гонять через браузер: её проверяет модульный тест функции и один API-тест.

Перевёрнутая пирамида («рожок мороженого») — много UI-тестов и почти нет модульных — типичная ошибка команд, которые начинают автоматизацию с записи сценариев в браузере. Такой набор идёт час, падает от каждой правки вёрстки, и его перестают запускать.

04

Инструменты

Набор автотестов собирают из нескольких инструментов, у каждого своя задача. В курсе — Python и его библиотеки; у других языков те же роли, другие названия.

РольВ курсеАналоги
Тестовый фреймворк: находит тесты, запускает, пишет отчётpytestJUnit (Java), Jest (JavaScript), xUnit (C#)
HTTP-клиент для API-тестовrequestsREST Assured, axios, HttpClient; Bruno и Postman — без кода
Управление браузеромPlaywrightSelenium WebDriver, Cypress
Проверка структуры JSONjsonschemaAjv, everit-json-schema
Отчёты и покрытиеpytest-html, JUnit XML, coverageAllure, JaCoCo, Istanbul
Непрерывная интеграция: запуск на каждый коммитGitLab CIGitFlic CI, GitHub Actions, Jenkins

API- и UI-тесты проверяют программу снаружи, по сети и через браузер, поэтому годятся для проекта на любом языке: ваш итоговый проект может быть на PHP или C#, а тесты к нему — на Python. Модульные тесты пишут на языке самой программы.

05

Как устроен рабочий набор

Для курса подготовлен стартовый проект — небольшой набор автотестов «Задачника». Скачайте архив qa-starter.zip и распакуйте в отдельную папку — в нём уже есть tasker.py. Состав:

$ find . -type f -not -path "*/__pycache__/*" | sort
./client.py
./conftest.py
./pytest.ini
./README.md
./requirements.txt
./tasker.py
./tests/test_smoke.py
ФайлЗачем
tests/test_smoke.pyСами тесты: пять проверок главного — страница входа, вход по API, свои задачи, создание и удаление, вход в браузере
conftest.pyОбщая подготовка для всех тестов: запуск «Задачника» на свободном порту со свежими данными, учётные записи, клиенты API (раздел 04)
client.pyКороткие вызовы API: api.get("/api/tasks") вместо полного адреса и заголовка с токеном (раздел 06)
pytest.iniНастройки pytest: где искать тесты, маркеры smoke и slow
requirements.txtЗакреплённые версии пакетов — у всех в группе одинаковые
README.mdКак установить и запустить — коротко, для того, кто открыл проект впервые
tasker.pyПроверяемое приложение; тесты запускают его сами, вручную запускать не нужно

Важное свойство набора: каждый прогон начинается с чистых учебных данных и не трогает вашу копию tasker.db. Тесты, которые создают задачи, работают под новым пользователем, созданным для этого теста. Поэтому тесты можно запускать в любом порядке и сколько угодно раз — результат один и тот же.

06

Первый запуск

Установка — один раз, в папке проекта. В Windows (PowerShell или командная строка):

py -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
playwright install chromium

В Linux — то же с python3 -m venv .venv и source .venv/bin/activate. Последняя команда скачивает браузер Chromium для UI-тестов — сотни мегабайт, это займёт несколько минут; браузер ставится один раз на компьютер и подходит всем проектам с той же версией Playwright. Что делает каждая команда, разберём в разделе 02; если PowerShell не даёт выполнить activate, запустите один раз Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.

Запуск — команда pytest в папке проекта:

$ pytest
============================= test session starts ==============================
platform linux -- Python 3.13.5, pytest-9.2.0, pluggy-1.7.0
rootdir: ~/qa/starter
configfile: pytest.ini
testpaths: tests
plugins: metadata-3.1.1, playwright-0.10.0, locust-2.47.0, html-4.2.0
collected 5 items

tests/test_smoke.py .....                                                [100%]

============================== 5 passed in 1.87s ===============================

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

$ pytest -v
============================= test session starts ==============================
platform linux -- Python 3.13.5, pytest-9.2.0, pluggy-1.7.0 -- ~/qa/.venv/bin/python3
cachedir: .pytest_cache
metadata: {'Python': '3.13.5', 'Platform': 'Linux-6.12.95+deb13-amd64-x86_64-with-glibc2.41', 'Packages': {'pytest': '9.2.0', 'pluggy': '1.7.0'}, 'Plugins': {'metadata': '3.1.1', 'playwright': '0.10.0', 'locust': '2.47.0', 'html': '4.2.0'}}
rootdir: ~/qa/starter
configfile: pytest.ini
testpaths: tests
plugins: metadata-3.1.1, playwright-0.10.0, locust-2.47.0, html-4.2.0
collecting ... collected 5 items

tests/test_smoke.py::test_login_page_opens PASSED                        [ 20%]
tests/test_smoke.py::test_api_login_gives_token PASSED                   [ 40%]
tests/test_smoke.py::test_ivan_sees_own_tasks PASSED                     [ 60%]
tests/test_smoke.py::test_create_and_delete PASSED                       [ 80%]
tests/test_smoke.py::test_ui_login[chromium] PASSED                      [100%]

============================== 5 passed in 1.58s ===============================

У теста в браузере в имени добавился [chromium] — так pytest-playwright отмечает браузер, в котором шёл тест. Маркер slow позволяет пропустить медленные тесты, когда нужен быстрый ответ:

$ pytest -m "not slow"
============================= test session starts ==============================
platform linux -- Python 3.13.5, pytest-9.2.0, pluggy-1.7.0
rootdir: ~/qa/starter
configfile: pytest.ini
testpaths: tests
plugins: metadata-3.1.1, playwright-0.10.0, locust-2.47.0, html-4.2.0
collected 5 items / 1 deselected / 4 selected

tests/test_smoke.py ....                                                 [100%]

======================= 4 passed, 1 deselected in 0.27s ========================
07

Как читать падение

Чтобы увидеть упавший тест, испортим ожидание: пусть тест считает, что у ivan 9 задач, а не 8.

$ pytest -m "not slow"
============================= test session starts ==============================
platform linux -- Python 3.13.5, pytest-9.2.0, pluggy-1.7.0
rootdir: ~/qa/starter
configfile: pytest.ini
testpaths: tests
plugins: metadata-3.1.1, playwright-0.10.0, locust-2.47.0, html-4.2.0
collected 5 items / 1 deselected / 4 selected

tests/test_smoke.py ..F.                                                 [100%]

=================================== FAILURES ===================================
___________________________ test_ivan_sees_own_tasks ___________________________

ivan = <client.Api object at 0x7f6b540b3890>

    def test_ivan_sees_own_tasks(ivan):
        tasks = ivan.get("/api/tasks").json()
>       assert len(tasks) == 9
E       AssertionError: assert 8 == 9
E        +  where 8 = len([{'id': 4, 'title': 'Отчёт по продажам за сентябрь', 'due': '2026-10-26', 'priority': 2, ...}, {'id': 1, 'title': 'Под...', 'priority': 1, ...}, {'id': 8, 'title': 'Заказать пропуск для гостя', 'due': '2026-11-02', 'priority': 3, ...}, ...])

tests/test_smoke.py:21: AssertionError
=========================== short test summary info ============================
FAILED tests/test_smoke.py::test_ivan_sees_own_tasks - AssertionError: assert...
================== 1 failed, 3 passed, 1 deselected in 0.32s ===================

Отчёт о падении читают сверху вниз:

  1. F в строке прогресса — какой по счёту тест упал.
  2. Блок FAILURES — имя теста и его код; строка со стрелкой > — проверка, которая не выполнилась.
  3. Строки E — что было на самом деле: pytest сам показал, что len(tasks) равно 8, а ожидалось 9.
  4. Последняя строка блока — файл и номер строки. С неё начинают разбор.
  5. short test summary info — краткий список всех упавших: удобно, когда их много.

Упавший автотест — не баг-репорт. Сначала нужно понять, кто неправ: программа, тест или окружение. Здесь неправ тест: ожидание 9 ничем не обосновано. Если бы тест опирался на требование, а программа его нарушала, — это дефект, и тогда оформляют баг-репорт по правилам курса ручного тестирования, а в отчёт прикладывают вывод теста.

Ключевые выводы раздела

Запомните главное

  • Автотест сам выполняет проверку и сам сравнивает результат с ожиданием — но видит только то, что в нём написано
  • Автоматизируют повторяющееся: регресс, варианты данных, API, расчёты; удобство и исследование остаются людям
  • Пирамида: много модульных, меньше API, немного UI; проверку делают на самом низком уровне, где она возможна
  • Набор полезен, только если ему доверяют: независимые тесты, чистые данные, никаких случайных падений
  • Падение читают с последней строки блока FAILURES и сначала решают, кто неправ — программа, тест или окружение
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Все разделы Раздел 02: Python для автотестов