Раздел 02 — Python для автотестов

Ровно столько Python, сколько нужно, чтобы читать и писать тесты

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

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

8 академических часов: 2 теории, 6 практики. Если Python вы уже знаете, раздел можно пройти быстро: прочитайте примеры и сделайте задания портала. Полный курс языка — «Python с нуля».
01

Python, VS Code и виртуальное окружение

Python — с python.org, версия 3.10 или новее. В Windows при установке отметьте «Add python.exe to PATH»; запускается командой py. В Linux Python уже есть, команда — python3. VS Code — с code.visualstudio.com, в нём расширение Python от Microsoft (вкладка Extensions, Ctrl+Shift+X).

Виртуальное окружение (venv) — папка .venv внутри проекта со своей копией Python и своими пакетами. Зачем: у каждого проекта свои версии pytest и Playwright, и они не мешают друг другу и системе. Окружение не переносят и не кладут в git — его создают заново командой.

ДействиеWindowsLinux
Создать окружениеpy -m venv .venvpython3 -m venv .venv
Включить.venv\Scripts\activatesource .venv/bin/activate
Признак, что включеноВ начале строки приглашения — (.venv); команда python — уже из окружения
Поставить пакетыpip install -r requirements.txt
Выключитьdeactivate

Файл requirements.txt перечисляет пакеты с точными версиями — так у всей группы и в CI одинаковый набор:

# Пакеты курса «QA: автоматизация тестирования» — nevabit.ru/qa-automation/
# Установка: pip install -r requirements.txt, затем: playwright install chromium
pytest==9.2.0
requests==2.34.2
jsonschema==4.26.0
playwright==1.64.0
pytest-playwright==0.10.0
pytest-html==4.2.0
coverage==7.17.0

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

$ pip list | grep -iE "^(pytest|requests|playwright|jsonschema) "
jsonschema                4.26.0
playwright                1.64.0
pytest                    9.2.0
requests                  2.34.2
$ python -c "import requests; print(requests.__version__)"
2.34.2
$ python -c "import reqests"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import reqests
ModuleNotFoundError: No module named 'reqests'

В VS Code: File → Open Folder — папка проекта; внизу справа выберите интерпретатор из .venv (или Ctrl+Shift+P → «Python: Select Interpreter»). Тогда встроенный терминал (Ctrl+`) сразу открывается с включённым окружением.

02

Значения: строки, числа, логические

Переменная получает значение знаком =, тип объявлять не нужно. Для тестов важнее всего строки: названия, сообщения об ошибках, тексты страниц.

title = "  Купить картридж  "
priority = 2
done = False

clean = title.strip()
print(clean)
print(len(title), len(clean))
print(f"Задача «{clean}», приоритет {priority}")
print(clean.upper())
print("картридж" in clean)
print(clean[:6], clean[-8:])
print(type(priority), type(clean), type(done))
print(int("42") + 1, str(42) + "1")
$ python values.py
Купить картридж
19 15
Задача «Купить картридж», приоритет 2
КУПИТЬ КАРТРИДЖ
True
Купить картридж
<class 'int'> <class 'str'> <class 'bool'>
43 421
03

Списки и словари

Ответ API — почти всегда список словарей: список задач, у каждой поля id, title, priority. Поэтому эти два типа — главные в автотестах.

titles = ["Позвонить поставщику", "Обновить прайс-лист"]
titles.append("Заказать пропуск")
print(titles)
print(len(titles), titles[0], titles[-1])

task = {"id": 7, "title": "Обновить прайс-лист", "priority": 3, "due": None}
print(task["title"], task["priority"])
task["status"] = "new"
print(task.get("due"), task.get("owner", "нет поля"))
print(list(task.keys()))

tasks = [
    {"title": "Отчёт", "priority": 1, "status": "done"},
    {"title": "Звонок", "priority": 2, "status": "new"},
    {"title": "Пропуск", "priority": 3, "status": "new"},
]
new_titles = [t["title"] for t in tasks if t["status"] == "new"]
print(new_titles)
print({t["title"]: t["priority"] for t in tasks})
$ python collections_demo.py
['Позвонить поставщику', 'Обновить прайс-лист', 'Заказать пропуск']
3 Позвонить поставщику Заказать пропуск
Обновить прайс-лист 3
None нет поля
['id', 'title', 'priority', 'due', 'status']
['Звонок', 'Пропуск']
{'Отчёт': 1, 'Звонок': 2, 'Пропуск': 3}
ЗаписьЧто делает
titles[0], titles[-1]Первый и последний элемент списка
task["title"]Значение по ключу; нет ключа — ошибка KeyError
task.get("owner", "нет поля")Значение или запасное, без ошибки
[t["title"] for t in tasks if …]Списковое включение: новый список из подходящих элементов. В тестах так достают названия из ответа
{t["title"]: t["priority"] for t in tasks}То же для словаря

None — «значения нет». В JSON это null: у задачи без срока поле due равно None. Проверяют его через is None.

04

Условия, циклы, функции

Блоки выделяются отступом в 4 пробела — это часть синтаксиса, а не оформление. Функция объявляется словом def, у параметров могут быть значения по умолчанию.

def check_priority(value, low=1, high=5):
    """Вернуть текст ошибки или None, если приоритет допустим."""
    if not isinstance(value, int):
        return "приоритет — целое число"
    if value < low or value > high:
        return f"приоритет от {low} до {high}"
    return None


for value in [0, 1, 5, 6, "3"]:
    error = check_priority(value)
    if error is None:
        print(value, "— допустимо")
    else:
        print(value, "—", error)

print(check_priority(7, high=10))

count = 0
while count < 3:
    count += 1
print("повторов:", count)
$ python control.py
0 — приоритет от 1 до 5
1 — допустимо
5 — допустимо
6 — приоритет от 1 до 5
3 — приоритет — целое число
None
повторов: 3
05

Исключения

Исключение — сигнал «дальше выполнять нельзя». try … except перехватывает его, raise вызывает. Необработанное исключение останавливает программу и печатает трассировку — по ней ищут место ошибки:

def parse_priority(text):
    try:
        value = int(text)
    except ValueError:
        return None
    return value


print(parse_priority("4"), parse_priority("четыре"))


def need_title(title):
    if not title.strip():
        raise ValueError("пустое название")
    return title.strip()


try:
    need_title("   ")
except ValueError as err:
    print("ошибка:", err)

print(need_title("  Отчёт "))
need_title("")
$ python errors.py
4 None
ошибка: пустое название
Отчёт
Traceback (most recent call last):
  File "~/qa/errors.py", line 24, in <module>
    need_title("")
    ~~~~~~~~~~^^^^
  File "~/qa/errors.py", line 14, in need_title
    raise ValueError("пустое название")
ValueError: пустое название

Трассировку читают снизу вверх: последняя строка — тип и текст ошибки, выше — где она возникла (line 14, функция need_title) и откуда вызвана (line 24). Так же устроен отчёт pytest о падении теста — раздел 03.

В тестах исключения почти не перехватывают: упавший тест и должен упасть. Исключение — проверка «функция обязана выбросить ошибку», для неё в pytest есть pytest.raises (раздел 03).
06

JSON и файлы

JSON — текстовый формат, в котором API передаёт данные. Модуль json превращает текст в словари и списки Python (loads) и обратно (dumps). pathlib.Path — путь к файлу с методами чтения и записи.

import json
from pathlib import Path

text = '{"id": 3, "title": "Обновить прайс-лист", "due": null, "overdue": false}'
task = json.loads(text)
print(task)
print(task["due"] is None, task["overdue"])

task["priority"] = 2
print(json.dumps(task, ensure_ascii=False))

path = Path("task.json")
path.write_text(json.dumps(task, ensure_ascii=False, indent=2), encoding="utf-8")
print(path.read_text(encoding="utf-8"))
loaded = json.loads(path.read_text(encoding="utf-8"))
print(loaded == task)
$ python data.py
{'id': 3, 'title': 'Обновить прайс-лист', 'due': None, 'overdue': False}
True False
{"id": 3, "title": "Обновить прайс-лист", "due": null, "overdue": false, "priority": 2}
{
  "id": 3,
  "title": "Обновить прайс-лист",
  "due": null,
  "overdue": false,
  "priority": 2
}
True
JSONPython
{"a": 1} объектdict
[1, 2] массивlist
"текст"str
1, 2.5int, float
true / falseTrue / False
nullNone

ensure_ascii=False оставляет кириллицу читаемой, без него будет О…. encoding="utf-8" при работе с файлами указывайте всегда: в Windows по умолчанию другая кодировка, и русский текст превратится в «кракозябры».

07

Модули и импорт

Каждый файл .py — модуль. Общий код выносят в отдельный файл и импортируют: так в наборе тестов живут клиент API (client.py) и страницы-объекты (раздел 09).

"""Модуль с общими функциями: его импортируют другие файлы."""
STATUSES = {"new": "Новая", "in_progress": "В работе", "done": "Готово"}


def status_name(code):
    return STATUSES.get(code, "неизвестный статус")
import helpers
from helpers import status_name

print(helpers.STATUSES["done"])
print(status_name("in_progress"), "/", status_name("closed"))
$ python main.py
Готово
В работе / неизвестный статус

import helpers — обращение через имя модуля: helpers.STATUSES. from helpers import status_name — имя функции напрямую. Python ищет модуль в папке запускаемого файла и в установленных пакетах; pytest в нашем проекте дополнительно ищет в корне проекта — это настройка pythonpath = . в pytest.ini.

08

Запуск и отладка в VS Code

Запуск файла — кнопка ▶ справа вверху или Ctrl+F5. Отладка — F5 → «Python Debugger: Current File». Перед этим поставьте точку останова: щелчок слева от номера строки, появится красная точка.

КлавишаЧто делает в отладке
F10Выполнить строку, не заходя в функции
F11Зайти внутрь вызываемой функции
Shift+F11Выйти из функции
F5Продолжить до следующей точки останова

Слева на панели «Run and Debug» видны значения переменных в момент остановки — это быстрее, чем расставлять print. Тесты отлаживают так же: на вкладке Testing (значок колбы) VS Code находит тесты pytest, а у каждого теста есть кнопка «Debug Test». Настроить: Ctrl+Shift+P → «Python: Configure Tests» → pytest → папка проекта.

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

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

  • У каждого проекта своё окружение .venv, пакеты ставят из requirements.txt с точными версиями
  • Ответ API в Python — список словарей; поля достают по ключу, нужные значения — списковым включением
  • Отступы — синтаксис; функции с параметрами по умолчанию делают тесты короче
  • Трассировку исключения читают снизу вверх: тип ошибки, место, откуда вызвано
  • json.loads / json.dumps, а у файлов — всегда encoding="utf-8"
  • Общий код — в модули; отладка в VS Code быстрее, чем print
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Раздел 01: Автоматизация тестирования Все разделы Раздел 03: pytest — первые тесты