Контрактное тестирование
Что это такое
Контрактное тестирование проверяет, что реализация и описание API всё ещё совпадают: описание выступает контрактом, по которому и судят о коде. Тесты либо отправляют настоящие запросы к запущенному сервису и проверяют ответы по документу, либо порождают формы запросов и ответов из него и убеждаются, что сервер их принимает и выдаёт, — расхождение в любом случае становится упавшей сборкой, а не обращением в поддержку.
Почему это важно
Спецификация, которую никто не проверяет, остаётся просто документацией, а документация расходится. Как только реализацию правят без документа, сгенерированный клиент перестаёт компилироваться, а опубликованная документация начинает врать. Контрактные тесты делают это расхождение видимым в момент его появления, когда исправление — однострочная правка схемы, а не когда сломался клиент, — и именно они делают правдой утверждение о единственном источнике из предыдущего урока.
Ключевые идеи
Документ — это утверждение, а не побочный продукт
Генерация документации из аннотаций в коде даёт описание того, что код делает, включая его случайности. Если же источником считать документ и проверять код по нему, получится описание того, что API обещает. Первое удобно, но ошибку поймать не способно; второе — способно.
документ (источник истины) -> проверка живых ответов -> успех или провал
Проверяйте настоящие ответы по схемам
Запрос к запущенному сервису и проверка тела и кода ответа по схеме ловят переименованное поле, расширенный тип или изменённый код; запустив это для каждой описанной операции, вы получите покрытие, которое соответствует документу, а не воображению автора теста.
Схемы должны быть строгими к неожиданным полям
Валидатор, который игнорирует неизвестные поля в ответе, не заметит вновь добавленное поле, а это часто первый признак несовместимого изменения; если явно ответить, допустимы ли дополнительные поля, документ станет ещё и инструментом затягивания гаек, а не только проверкой.
Контракты, движимые потребителем, проверяют обратное направление
То, что производитель проверил собственные ответы, доказывает соответствие API его описанию, а не то, что клиенты довольны. При подходе, движимом потребителем, каждый клиент публикует отправляемые им запросы и требуемые ответы, и сборка производителя падает, если она сломает известного потребителя. Так удаления полей ловятся до выпуска, а не после.
Контрактные тесты быстры и должны идти на каждое изменение
Поскольку проверяют они формы интерфейса, а не поведение целиком, запускать их можно на каждом коммите — а именно там они и полезнее всего; проверка контракта, которая идёт ночью, находит расхождение на день позже, а та, что идёт на запросе на слияние, — до слияния.
Версионирование и контракты — одна дисциплина
Контрактный тест не даёт незаметно выпустить случайное ломающее изменение. Однако если изменение ломающее намеренно, версию поднимают осознанно, а старый контракт продолжает соблюдаться, пока не закроется окно устаревания. Соблюдение этого расписания как раз тест и обеспечивает.
Практика
Проверяйте ответы по документу
Напишите тест, который отправляет запрос для каждой описанной операции и проверяет каждый ответ по его схеме, включая ответы с ошибкой.
Готово, когда: изменение поля ответа в реализации без правки документа валит тест.
Обнаружьте недокументированное добавление
Добавьте поле в ответ, не объявив его, и убедитесь, что проверка его находит.
Готово, когда: лишнее поле обнаружено, и вы решили, должна ли схема запрещать дополнительные свойства.
Частые ошибки
- Генерация документа из кода под видом контракта — описание следует за ошибками, а не предотвращает их; исправить: считайте документ источником и проверяйте по нему.
- Проверка только успешных ответов — форма ошибки расходится незаметно; исправить: проверяйте каждый описанный ответ.
- Молчаливое разрешение неизвестных полей — неожиданные добавления проходят; исправить: решите и обеспечьте, допустимы ли дополнительные поля.
- Редкий запуск проверок контракта — расхождение находится после выпуска; исправить: запускайте их на каждое изменение.
- Проверка только собственных обещаний производителя — требования потребителя остаются непроверенными; исправить: применяйте контракты, движимые потребителем, там, где клиенты известны.
Что читать дальше
- Написание спецификации (05-backend-data/09-api-design-openapi-swagger/01-writing-the-specification) — документ, по которому утверждают эти тесты.
- Проектирование API (OpenAPI / Swagger) (05-backend-data/09-api-design-openapi-swagger) — формат и инструменты, которые использует эта практика.
- CI/CD (06-cloud-devops/08-ci-cd) — этап конвейера, где провал контракта блокирует слияние.