🐛 Типичные ошибки при работе с requests

← К оглавлению урока

⚡ Топ-5 ошибок

  1. Не проверить status_code — тест молча проходит при ошибке 422/500
  2. data= вместо json= — неверный Content-Type, сервер вернёт 422
  3. Вызов .json() при не-JSON ответе — JSONDecodeError
  4. Нет timeout — тест зависает навсегда при проблемах с сетью
  5. Хардкод ID в тесте — тест падает когда ID меняется или запись удалена

Ошибка 1: Не проверять status_code

Тест без проверки статуса может «пройти» даже при ошибке сервера.

Неправильно

# test_bad.py — опасно!
def test_create_company():
    resp = requests.post(BASE_URL + "/company/create", json={"name": "Test"})
    # Нет assert — тест всегда проходит, даже если сервер вернул 500!

Правильно

# test_good.py
def test_create_company():
    resp = requests.post(BASE_URL + "/company/create", json={"name": "Test"})
    assert resp.status_code == 201, f"Ожидался 201, получен {resp.status_code}"
    assert resp.json()["name"] == "Test"

Ошибка 2: data= вместо json=

data={"name": "Test"} отправляет форму (application/x-www-form-urlencoded), а не JSON.

Неправильно

# Отправляет как HTML-форму, Content-Type: application/x-www-form-urlencoded
resp = requests.post(url, data={"name": "Test", "description": "Desc"})
# Сервер ожидает JSON → вернёт 422 Unprocessable Entity

Правильно

# Отправляет JSON, Content-Type: application/json выставляется автоматически
resp = requests.post(url, json={"name": "Test", "description": "Desc"})
assert resp.status_code == 201
Правило: если API ожидает JSON — используй json=. Если API ожидает форму (HTML form submit) — используй data=.

Ошибка 3: .json() при не-JSON ответе

Симптом

requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Причина и решение

# Плохо — без проверки Content-Type
resp = requests.get("https://example.com")
data = resp.json()  # JSONDecodeError! Сервер вернул HTML

# Хорошо — сначала проверить тип контента
resp = requests.get(url)
if "application/json" in resp.headers.get("Content-Type", ""):
    data = resp.json()
else:
    print("Ответ не JSON:", resp.text[:200])

# Или — обработать исключение
try:
    data = resp.json()
except requests.exceptions.JSONDecodeError:
    raise AssertionError(f"Ответ не является JSON: {resp.text[:200]}")

Ошибка 4: Отсутствие timeout

Симптом

Тест «висит» несколько минут при проблемах с сетью или сервером.

Решение

# Без timeout — тест может зависнуть
resp = requests.get("http://5.101.50.27:8000/company/list")

# С timeout (рекомендуется всегда!)
resp = requests.get(
    "http://5.101.50.27:8000/company/list",
    timeout=10  # 10 секунд — разумное значение для API-тестов
)

# timeout=(connect_timeout, read_timeout)
resp = requests.get(url, timeout=(3, 10))  # 3 сек на подключение, 10 на чтение

Ошибка 5: Хардкод ID в тесте

Неправильно

# Плохо — ID 42 может не существовать или измениться
def test_get_company():
    resp = requests.get(BASE_URL + "/company/42")
    assert resp.status_code == 200  # Может упасть!

Правильно

# Хорошо — сначала создаём, потом используем полученный ID
def test_get_company():
    # Создаём компанию и получаем её ID
    create_resp = requests.post(BASE_URL + "/company/create",
                                json={"name": "Test", "description": "temp"})
    assert create_resp.status_code == 201
    company_id = create_resp.json()["id"]

    # Теперь используем реальный ID
    resp = requests.get(BASE_URL + f"/company/{company_id}")
    assert resp.status_code == 200
    assert resp.json()["name"] == "Test"

Ошибка 6: Перепутать json.loads() и resp.json()

# Избыточно — json.loads(resp.text) делает то же, что resp.json()
import json
resp = requests.get(url)
data = json.loads(resp.text)  # Работает, но лишний шаг

# Правильно — используй встроенный метод
data = resp.json()  # Короче, читаемее, то же самое

Ошибка 7: Некорректный JSON в теле запроса

# Ошибка в исходниках лекции: одинарные кавычки в JSON — невалидно!
invalid = "{ 'name': 'Test' }"   # JSON требует двойные кавычки!

import json
try:
    json.loads(invalid)
except json.JSONDecodeError as e:
    print(f"Ошибка: {e}")
    # json.JSONDecodeError: Expecting property name enclosed in double quotes

# Правильно: использовать двойные кавычки в JSON-строках
valid = '{"name": "Test"}'
data = json.loads(valid)  # {'name': 'Test'}