🐛 Типичные ошибки при работе с requests
⚡ Топ-5 ошибок
- Не проверить status_code — тест молча проходит при ошибке 422/500
- data= вместо json= — неверный Content-Type, сервер вернёт 422
- Вызов .json() при не-JSON ответе — JSONDecodeError
- Нет timeout — тест зависает навсегда при проблемах с сетью
- Хардкод 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'}