Тест интеграции проверяет JSON-ответ только по схеме типов, но не сверяет сумму позиций с полем total. Какой дефект такой тест может пропустить?
Такой тест может пропустить семантическое нарушение контракта: например, сервер вернёт числовые поля правильного типа, но значение total не будет равно сумме позиций. Проверка схемы подтверждает структуру и типы данных, однако не подтверждает бизнес-инварианты, связывающие несколько полей.
Схемы ответов появились как способ формально описывать структуру сообщений между независимыми системами: обязательные поля, типы, допустимые форматы и вложенность. Это устраняет часть ошибок интеграции, связанных с несовместимым JSON.
Однако структурная проверка не отвечает на вопрос, согласованы ли значения между собой. Поэтому поверх схемы используют семантические проверки — утверждения о смысле данных и отношениях между их полями.
Сервер может вернуть массив позиций, корректные числовые значения цены и количества, а также поле total типа «число». Формально такой ответ соответствует схеме даже в случае ошибки расчёта, округления, применения скидки или включения лишней позиции.
Если интеграционный тест проверяет только схему, дефект обнаружится поздно: его может заметить пользователь, бухгалтерская система или другой сервис-потребитель. Особенно опасна ситуация, когда разные сервисы самостоятельно пересчитывают итог и получают разные суммы.
Интеграционный тест должен проверять не только структурный контракт, но и релевантные семантические инварианты. В данном случае нужно определить бизнес-правило: например, total равен сумме позиций с учётом документированных скидок, налогов и правил округления.
Проверка должна использовать независимый от реализации расчёт теста. Нельзя просто вызвать тот же production-код вычисления суммы, потому что одинаковая ошибка в коде приложения и тесте даст ложный успех.
Важно явно зафиксировать правила:
Для денежных значений обычно предпочтительны целые минимальные единицы валюты либо десятичная арифметика. Если контракт допускает расхождение из-за округления, тест должен проверять документированный допуск, а не произвольное точное равенство.
Семантические проверки не заменяют схему. Схема быстро выявляет отсутствие поля или неверный тип, а инварианты проверяют согласованность и смысл данных. При этом не следует дублировать все внутренние правила сервиса: интеграционный тест должен проверять только внешний контракт, значимый для потребителя.
Интеграционный тест заказа проверял наличие идентификатора, списка позиций, цен и итоговой суммы, а также соответствие JSON-схеме. После изменения расчёта скидки тест продолжил проходить, хотя клиент показывал покупателю сумму без учёта скидки, а платёжный сервис списывал другую сумму.
Рассматривались два варианта. Первый — проверять только фиксированный полный ответ; это просто, но плохо выявляет причину ошибки и делает тест хрупким при допустимых изменениях данных. Второй — проверять независимые инварианты: состав позиций, правила скидки, итоговую сумму и формат денег; такой подход требует точнее описать контракт, зато отделяет бизнес-дефект от косметических изменений ответа.
Выбрали второй вариант: тест создавал заказ с несколькими позициями, скидкой и пограничным округлением, затем независимо рассчитывал ожидаемые значения по правилам внешнего контракта. В результате ошибка порядка округления была обнаружена на интеграционном уровне до выпуска, а тест не зависел от внутренней реализации расчётного модуля.
1. Достаточно ли сравнить total с суммой цен всех позиций?
Нет. Нужно учитывать полный контракт расчёта: количество, скидки, налоги, доставку, валюту и правила округления. Простая сумма цен может сама быть неверной ожидаемой моделью и создать ложные падения теста.
2. Почему нельзя переиспользовать в тесте функцию расчёта из production-кода?
Если функция содержит дефект, тест воспроизведёт тот же дефект и подтвердит ошибочный результат. Независимая проверка должна быть проще и основываться на контракте, тестовых данных и явно заданных правилах, а не на том же алгоритме.
3. Нужно ли проверять все бизнес-инварианты в каждом интеграционном тесте?
Нет. Следует проверять инварианты, являющиеся частью внешнего контракта конкретного потребителя, особенно те, нарушение которых приводит к финансовым, юридическим или межсервисным ошибкам. Остальные правила лучше покрывать модульными или специализированными тестами, чтобы интеграционные проверки оставались понятными и не становились избыточно медленными.