Должен ли я проверить все перечисляемые значения в контракте?

У меня есть сомнения относительно того, должен ли я рассматривать определенный тип тестового функционала или контракт.

Допустим, у меня есть API, подобный /getToolType, который принимает {object" "myObject"} в качестве входных данных и возвращает тип в виде {type: "[az]+"}

Между клиентом и сервером было согласовано, что возвращаемые типы будут соответствовать набору строк, скажем, [hammer|knife|screwdriver], поэтому потребитель решил проанализировать их в перечислении со значением отката, когда возвращаемый тип неизвестен.

Если потребитель включает тестовый набор для каждого типа (молоток, нож, отвертка), чтобы убедиться, что производитель все еще соблюдает соглашение о том, что он всегда будет возвращать, например, строчную строку "hammer", когда / getToolType вызывается с объектом hammer? Или вы считаете такой тестовый пример функциональным? И почему?

3 ответа

Решение

Отличный вопрос Короткий ответ: нет правильного или неправильного пути, просто как вы хотите это сделать.

Более длинный ответ:

Суть Pact (и контрактного тестирования) заключается в тестировании конкретных сценариев и проверке их соответствия. Вы можете просто в своем контракте создать регулярное выражение, которое допускает любой тип строки для этих перечислений, или может быть нулевым, но только если ваш потребитель просто не заботится об этом значении. Например, если бы у типа инструмента был бренд, я бы не заботился о бренде, просто он возвращался обратно в виде строки, так как я просто отображал дословно бренд на потребителе (front-end).

Однако, если бы это зависело от меня, исходя из того, что я понимаю в вашем сценарии, кажется, что тип инструмента на самом деле очень важен, учитывая конечную точку, к которой он относится, поэтому, вероятно, у меня были бы конкретные тесты и контракты для каждого перечисления, чтобы убедиться, что определенные сценарии для моего потребителя действительны (я называю X чем-то и ожидаю, что Y будет иметь инструмент типа Z).

Оба эти решения верны, к чему они сводятся: как вы думаете, какой тип инструмента важен для потребителя? Если это так, создайте специфичные для него контракты, если нет, то просто создайте общий контракт.

Надеюсь, это поможет.

ИМО короткий ответ "нет".

Контрактное тестирование больше интересует структура, если мы начнем граничное тестирование API, мы перейдем на территорию функционального тестирования [1], что лучше всего сделать в базе кода провайдера. Вы можете использовать средство сопоставления, чтобы гарантировать, что возвращается только одно из этих трех значений, это должно гарантировать, что сборка поставщика не может возвращать другие значения.

Я хотел бы повторить комментарии @J_A_X - нет правильного или неправильного ответа, просто будьте осторожны с проверкой всех перестановок входных / выходных данных.

[1] https://docs.pact.io/best_practices/contract_tests_not_functional_tests.html

Правильное состояние состоит в том, что потребитель потребляет молоток, нож и отвертку, c = (молоток, нож, отвертка) для краткости, а производитель производит молоток, нож и отвертку, p = (молоток, нож, отвертка). Существует четыре сценария регрессии:

  1. c=(молоток,нож,отвертка,меч), ​​p=(молоток,нож,отвертка)
  2. c=(молоток,нож,отвертка), p=(молоток,нож,отвертка,меч)
  3. c=(молоток,нож,отвертка), p=(молоток,нож)
  4. c=(молоток,нож), p=(молоток,нож,отвертка)

1 и 3 очень мягко нарушают контракт. В первом сценарии заказчик объявил новый тип, который (пока) не поддерживается производителем. В третьем сценарии производитель прекращает поддержку типа. Серьезность сценариев, конечно, может вызывать опасения, поскольку то, что я считаю мягкой регрессией, может быть в определенной службе в важном для бизнеса процессе. Однако, если это критично, есть значительная мотивация покрыть это специальным тестовым примером. 2-й и 4-й сценарии более серьезны, в обоих случаях потребитель может столкнуться с ошибкой, например, не сможет десериализовать данные.

Наличие контрольного примера для каждого типа должно обнаруживать сценарии 3 и 4. В первом сценарии это может привести к тому, что разработчик создаст дополнительный тестовый пример, который не сработает на сайте-производителе. Однако тестовые случаи беспомощны против 2-го сценария. Таким образом, несмотря на относительно высокую стоимость, эта стратегия не дает нам полного тестового покрытия.

Наличие одного тестового примера с регулярным выражением, охватывающим все допустимые типы (например, молоток|нож|отвертка), должно стать для разработчика-потребителя сильным триггером для изменения дизайна тестового примера в 1-м и 4-м сценариях. После того, как регулярное выражение настроено на новые потребительские возможности, оно может обнаружить сценарий 4 с вероятностью p=1/3 (т. е. тест завершится неудачей, если производитель выбрал отвертку в качестве выборочного значения). Даже без настройки регулярного выражения он обнаружит третий сценарий с p=1/3. Эта стратегия беспомощна против 1-го и 2-го сценария.

Однако помимо регулярного выражения мы можем сделать больше. А именно, мы можем разработать тестовый пример производителя со случайными данными. Предполагая, что рассматриваемый тип определен следующим образом:

      enum Tool {hammer,knife,screwdriver}

мы можем визуализировать тестовые данные с помощью:

      responseBody = Arranger.some(Tool.class);

Этот фрагмент кода использует test-arranger , но есть и другие библиотеки, которые могут делать то же самое. Он выбирает одно из допустимых значений перечисления. Каждый раз это может быть разное. Что это меняет? Теперь мы можем обнаружить 2-й сценарий и после настройки регулярного выражения 4-й. Таким образом, он охватывает самые тяжелые сценарии. Есть и недостаток, который следует учитывать. Тест производителя недетерминирован, в зависимости от полученного значения он может быть успешным или неудачным, что считается антипаттерном. Когда некоторые тесты иногда терпят неудачу, несмотря на то, что тестируемый код верен, люди начинают игнорировать результаты тестов. Обратите внимание, что тестовый пример производителя со случайными даннымиэто не так, это на самом деле наоборот. Иногда это может быть успешным, несмотря на то, что тестируемый код неверен. Она все еще далека от совершенства, но это интересный компромисс, поскольку это первая стратегия, в которой удалось справиться с очень тяжелым вторым сценарием.

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

Другие вопросы по тегам