В качестве примера еще раз обратимся к нашему сценарию клиентского сервиса. У него есть два отдельных потребителя: сервис техподдержки и веб-магазин. У обоих этих сервисов-потребителей есть ожидания того, как будет вести себя клиентский сервис. В данном примере создаются два набора тестов: по одному для каждого потребителя, представляющего использование клиентского сервиса сервисом техподдержки и веб-магазином. Здесь правилом хорошего тона считается совместный вклад в создание тестов, вносимый как командами потребителей, так и командой поставщика, поэтому вполне вероятно, что их созданием будут заниматься представители команд сервиса техподдержки и веб-магазина с представителями команды клиентского сервиса.
Поскольку эти CDC являются ожиданиями того, как себя будет вести клиентский сервис, их можно запускать в отношении самого клиентского сервиса с любыми заглушенными нижестоящими по отношению к нему зависимостями (рис. 7.9). С точки зрения области действия эти контракты занимают тот же уровень в тестовой пирамиде, что и тесты сервисов, хотя и с совершенно иным фокусом (рис. 7.10). Эти тесты фокусируются на том, как сервис будет использоваться потребителем, и причины их сбоев совсем другие, нежели причины сбоев при проведении тестов сервиса. Если в ходе сборки клиентского сервиса будут нарушены эти CDC, станет совершенно понятно, на кого из потребителей это повлияет. В таком случае можно будет либо устранить проблему, либо обсудить внесение критических изменений в том порядке, который рассматривался в главе 4. Итак, используя CDC, можно идентифицировать критическое изменение до запуска программного средства в работу в производственном режиме без необходимости применения потенциально недешево обходящихся сквозных тестов.
Рис. 7.9. Тесты на основе запросов потребителей в контексте примера клиентского сервиса
Рис. 7.10. Интеграция тестов на основе запросов потребителей в тестовую пирамиду
Pact представляет собой средство тестирования на основе запросов потребителей, которое первоначально было разработано для внутренних нужд компании Real-Estate.com.au, а теперь является средством с открытым кодом, основной разработкой которого руководил Бет Скурри (Beth Skurrie). Предназначенное сначала только для Ruby средство тестирования Pact теперь включает порты JVM и. NET.
Блок-схема, приведенная на рис. 7.11, показывает, что Pact работает весьма интересным образом. Потребитель начинает с того, что определяет ожидания от производителя с использованием Ruby DSL. Затем вы запускаете локальный сервер-имитатор и в отношении его запускаете ожидания для создания файла спецификации Pact. Этот Pact-файл является не чем иным, как формальной JSON-спецификацией, которую вы, конечно, можете создать и вручную, но с использованием API-интерфейса языка это делается намного проще. Кроме того, вы получаете запущенный сервер-имитатор, который может применяться для последующих изолированных тестов потребителя.
Рис. 7.11. Обзор возможностей тестирования на основе запросов потребителей с использованием Pact
Затем с использованием JSON-спецификации Pact на стороне производителя проверяется соблюдение этой спецификации потребителя для управления вызовами вашего API-интерфейса и проверки ответов. Чтобы все это работало, набор исходных кодов производителя должен иметь доступ к Pact-файлу. Как уже говорилось в главе 6, ожидается, что потребитель и производитель будут находиться в разных сборках. Особенно приятной чертой является использование независимой от выбираемых языков программирования JSON-спецификации. Это означает, что создавать спецификацию потребителя можно с применением Ruby-клиента, но использовать ее для проверки Java-производителя с помощью принадлежащего Pact JVM-порта.
Поскольку JSON-спецификация Pact создается потребителем, это требует доступа к ней со стороны того артефакта, который создается поставщиком. Эту спецификацию можно сохранить в хранилище артефактов вашего CI/CD-средства или же можно воспользоваться средством Pact Broker, позволяющим хранить несколько версий ваших Pact-спецификаций. Это может позволить вам запускать тесты на основе потребительских запросов в отношении нескольких различных версий потребителей, если потребуется, скажем, применить тесты в отношении версии, используемой в производственном режиме, и в отношении версии, представленной самой последней сборкой.
Как ни странно, у компании ThoughtWorks имеется проект с открытым кодом под названием Pacto, который также является написанным на Ruby средством, использующимся для тестирования на основе запросов потребителей. У него есть возможность записи взаимодействий клиента и сервера для создания ожиданий. Это существенно упрощает создание контрактов для существующих сервисов, составленных на основе запросов потребителей. При использовании Pacto созданные ожидания имеют более или менее статичный характер, а с применением Pact ожидания создаются у потребителя с каждой новой сборкой. Функция определения ожиданий возможностей поставщика, которых пока еще нет, наилучшим образом вписывается в рабочий процесс, в рамках которого сервис-поставщик еще находится (или вскоре будет находиться) в разработке.
В обычной жизни истории называют заполнителями разговоров. CDC также можно рассматривать в данном ключе. Они становятся кодификацией ряда дискуссий о том, как должен выглядеть API-интерфейс сервиса, и когда контракты нарушаются, они становятся поводом для разговоров о том, как должен развиваться API-интерфейс.
Важно понимать, что CDC требуют активного обмена данными и доверия между потребителем и сервисом-поставщиком. Если обе стороны относятся к одной и той же команде (или это один и тот же человек!), то никаких трудностей возникать не должно. Но если вы являетесь потребителем сервиса, предоставляемого сторонним производителем, общение может быть нечастым или же могут отсутствовать доверительные отношения, способствующие работе CDC. В таких ситуациях вам, возможно, придется довольствоваться ограниченным числом интеграционных тестов с более широкой областью действия, охватывающей ненадежный компонент. Кроме того, если API-интерфейс создается для нескольких тысяч потенциальных потребителей, как в случае API общедоступного веб-сервиса, то для определения этих тестов вам, вероятно, придется играть роль потребителя самостоятельно (или же работать выборочно со своими потребителями). Игнорирование ожиданий огромного количества внешних потребителей нам не подойдет, поэтому ориентироваться нужно на возрастание важности CDC!
В данной главе уже были описаны во всех подробностях многие недостатки сквозных тестов, число которых по мере вовлечения в тестирование все большего количества активных компонентов стремительно растет. Из разговоров со специалистами, имевшими вполне достаточный опыт реализации микросервисов, я понял, что многие из них со временем полностью избавились от сквозных тестов, отдав предпочтение таким инструментам, как CDC, и уделив внимание совершенствованию мониторинга. Но выбрасывать эти тесты они все равно не спешили. Многие из сквозных маршрутных тестов стали использоваться для мониторинга системы, работающей в производственном режиме, с помощью технологии под названием «семантический мониторинг», которая более подробно рассматривается в главе 8.
Результаты сквозных тестов можно использовать, чтобы подстраховаться перед развертыванием для работы в производственном режиме. Пока вы будете вникать в характер работы CDC и совершенствовать производственный мониторинг и технологии развертывания, сквозные тесты могут стать весьма полезной страховочной сеткой при достижении разумного компромисса между временем цикла тестирования и уменьшением степени риска. Но при улучшениях в других областях можно приступать к сокращению зависимости от сквозных тестов вплоть до полного отказа от них.
Кроме того, ваша работа может проходить в такой обстановке, когда никто не будет стремиться к тому, чтобы быстрее запустить систему в производство и изучить ее поведение в ходе эксплуатации, и все силы будут брошены на избавление от дефектов до производственного развертывания системы, даже если это повлечет за собой затягивание сроков поставки программных продуктов. Пока вы не сможете обрести уверенность в том, что все источники дефектов устранены, и не поймете, что вам в процессе эксплуатации все же нужны эффективные средства мониторинга и внесения поправок, решение об использовании сквозных тестов может иметь под собой вполне разумные основания.
Разумеется, вы лучше меня сможете разобраться в управлении рисками в своей собственной организации, но я призываю как следует подумать о том, какие объемы тестирования реально нужны вашей системе.
Основной объем тестирования проводится перед развертыванием системы для работы в производственном режиме. Используя тесты, мы определяем ряд моделей, с помощью которых надеемся доказать, что система работает и ведет себя в соответствии с нашими пожеланиями как с функциональной, так и с нефункциональной точки зрения. Но если наши модели не отличаются совершенством, то при эксплуатации системы мы испытаем раздражение, столкнувшись с проблемами, ошибками, просочившимися в производство, обнаружением новых сбойных режимов работы и тем, что пользователи будут применять систему совершенно неожиданным для нас образом.
Одной из реакций на подобный результат зачастую является разработка все новых и новых тестов и улучшение моделей с целью отлова как можно большего количества дефектов на ранней стадии тестирования и сокращения количества проблем, с которыми приходится сталкиваться в системе, работающей в производственном режиме. Но в определенный момент нам приходится признавать, что отдача от такого подхода снижается. Тестированием, предшествующим развертыванию, мы не можем снизить вероятность сбоев до нуля.