Контрактное тестирование

Что это такое

Контрактное тестирование проверяет, что реализация и описание API всё ещё совпадают: описание выступает контрактом, по которому и судят о коде. Тесты либо отправляют настоящие запросы к запущенному сервису и проверяют ответы по документу, либо порождают формы запросов и ответов из него и убеждаются, что сервер их принимает и выдаёт, — расхождение в любом случае становится упавшей сборкой, а не обращением в поддержку.

Почему это важно

Спецификация, которую никто не проверяет, остаётся просто документацией, а документация расходится. Как только реализацию правят без документа, сгенерированный клиент перестаёт компилироваться, а опубликованная документация начинает врать. Контрактные тесты делают это расхождение видимым в момент его появления, когда исправление — однострочная правка схемы, а не когда сломался клиент, — и именно они делают правдой утверждение о единственном источнике из предыдущего урока.

Ключевые идеи

Документ — это утверждение, а не побочный продукт

Генерация документации из аннотаций в коде даёт описание того, что код делает, включая его случайности. Если же источником считать документ и проверять код по нему, получится описание того, что API обещает. Первое удобно, но ошибку поймать не способно; второе — способно.

документ (источник истины) -> проверка живых ответов -> успех или провал

Проверяйте настоящие ответы по схемам

Запрос к запущенному сервису и проверка тела и кода ответа по схеме ловят переименованное поле, расширенный тип или изменённый код; запустив это для каждой описанной операции, вы получите покрытие, которое соответствует документу, а не воображению автора теста.

Схемы должны быть строгими к неожиданным полям

Валидатор, который игнорирует неизвестные поля в ответе, не заметит вновь добавленное поле, а это часто первый признак несовместимого изменения; если явно ответить, допустимы ли дополнительные поля, документ станет ещё и инструментом затягивания гаек, а не только проверкой.

Контракты, движимые потребителем, проверяют обратное направление

То, что производитель проверил собственные ответы, доказывает соответствие API его описанию, а не то, что клиенты довольны. При подходе, движимом потребителем, каждый клиент публикует отправляемые им запросы и требуемые ответы, и сборка производителя падает, если она сломает известного потребителя. Так удаления полей ловятся до выпуска, а не после.

Контрактные тесты быстры и должны идти на каждое изменение

Поскольку проверяют они формы интерфейса, а не поведение целиком, запускать их можно на каждом коммите — а именно там они и полезнее всего; проверка контракта, которая идёт ночью, находит расхождение на день позже, а та, что идёт на запросе на слияние, — до слияния.

Версионирование и контракты — одна дисциплина

Контрактный тест не даёт незаметно выпустить случайное ломающее изменение. Однако если изменение ломающее намеренно, версию поднимают осознанно, а старый контракт продолжает соблюдаться, пока не закроется окно устаревания. Соблюдение этого расписания как раз тест и обеспечивает.

Практика

Проверяйте ответы по документу

Напишите тест, который отправляет запрос для каждой описанной операции и проверяет каждый ответ по его схеме, включая ответы с ошибкой.

Готово, когда: изменение поля ответа в реализации без правки документа валит тест.

Обнаружьте недокументированное добавление

Добавьте поле в ответ, не объявив его, и убедитесь, что проверка его находит.

Готово, когда: лишнее поле обнаружено, и вы решили, должна ли схема запрещать дополнительные свойства.

Частые ошибки

  • Генерация документа из кода под видом контракта — описание следует за ошибками, а не предотвращает их; исправить: считайте документ источником и проверяйте по нему.
  • Проверка только успешных ответов — форма ошибки расходится незаметно; исправить: проверяйте каждый описанный ответ.
  • Молчаливое разрешение неизвестных полей — неожиданные добавления проходят; исправить: решите и обеспечьте, допустимы ли дополнительные поля.
  • Редкий запуск проверок контракта — расхождение находится после выпуска; исправить: запускайте их на каждое изменение.
  • Проверка только собственных обещаний производителя — требования потребителя остаются непроверенными; исправить: применяйте контракты, движимые потребителем, там, где клиенты известны.

Что читать дальше