Добрый день! Я хотел бы представить новый инструмент для end-to-end тестирования микросервисов – Catcher
logo


Зачем тестировать?


Зачем нужно e2e тестирование? Мартин Фаулер рекомендует избегать его в пользу более простых тестов.


Однако, чем выше находятся тесты — тем меньше переписывать. Юнит тесты переписываются почти полностью. На функциональные тесты также приходится тратить свое время в случае серьезного рефакторинга. End-to-end тесты же должны проверять бизнес логику, а она меняется реже всего.


К тому же, даже полное покрытие тестами всех микросервисов не гарантирует их корректного взаимодействия. Разработчики могут неправильно имплементировать протокол (ошибки в наименовании/типе данных).


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


И тесты каждого из задействованных сервисов будут зеленые.


А зачем автоматическое тестирование?


Действительно. На моем предыдущем месте работы решили, что тратить время на разворачивание автоматических тестов это слишком долго, сложно и дорого. Система не большая (10-15 микросервисов с общей кафкой). CTO решил, что «тесты не важны, главное чтобы система работала». Тестировали вручную на нескольких окружениях.


Как это выглядело (общий процесс):


  1. Договориться с другими разработчиками (выкатка всех микросервисов, участвующих в новом функционале)
  2. Выкатить все сервисы
  3. Подключиться к удаленной кафке (двойной ssh в dmz)
  4. Подключиться к логам k8s
  5. Вручную сформировать и отправить кафка сообщение (слава богу json)
  6. Смотреть логи, пытаясь понять, заработало или нет.

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


Во-первых, из-за того, что система распределенная — у нескольких сервисов были свои базы данных, в которых лежала информация о пользователях.


Во-вторых, кафка использовалась для постоянного хранения данных. Т.е. даже если информацию удалить/изменить в базе данных, сервис при перезагрузке все-равно прочитает ее обратно.


Как выглядела регистрация нового тестового пользователя (приблизительно):


  1. Ввод всяких данных (имени, почты и т.п.)
  2. Ввод личных данных (адрес, телефон, всякая налоговая информация)
  3. Ввод банковских данных (собственно, банковские данные)
  4. Ответить на 20-40 вопросов (вы уже чувствуете боль?)
  5. Пройти идентификацию IDNow (на dev окружении, слава богу отключили, на stage это в районе 5 минут или больше, т.к. их сэндбокс иногда перегружен)
  6. На этом шаге требуется открытие счета в сторонней системе и через фрон-энд ничего не сделаешь. Нужно идти по ssh на кафку и работать мок-сервером (отправить сообщение, что счет открыт)
  7. Далее нужно идти на другой фронт-энд в личный кабинет модератора и подтвердить пользователя.

Супер, пользователь зарегистрирован! Теперь еще немного дегтя: для некоторых тестов нужно больше чем 1 тестовый пользователь. И иногда с первого раза тесты не проходят.


А как происходит проверка нового функционала и подтверждение со стороны бизнес-команды?
Все то же самое нужно повторить на следующем окружении.


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


Еще у некоторых разработчиков (обычно у фронт-энда) были проблемы с подключением к кафке. И с багом в терминале при строке 80+ символов (не все знали про tmux).


Плюсы:


  • не нужно ничего настраивать/писать. Тестируй прямо на запущенном окружении.
  • не требует высокой квалификации (могут делать более дешевые специалисты)

Минусы:


  • занимает много времени (чем дальше, тем больше)
  • обычно тестируется только новая функциональность (непонятно, поломалась ли существующая)
  • часто на ручном тестировании заняты квалифицированные разработчики (дорогие специалисты делают дешевую работу).

Как автоматизировать?


Если вы дочитали до сюда кивая головой и приговаривая: «да, отличный процесс, парни знают что делают», то дальше вам будет не интересно.


Самодельные e2e тесты бывают двух типов и зависят от того, какой из программистов был более свободен:


  • бэкэнд, который живет у вас в тестируемом окружении. В нем зашита логика тестирования, которая дергается через эндпоинты. Может быть даже частично автоматизирован благодаря взаимодейтсвию с CI.
  • Скрипт, с той же самой зашитой логикой. Разница только в том, что нужно зайти куда-нибудь и оттуда его запустить. Если вы доверяете своему CI, то вы даже можете запускать его автоматически.

Звучит неплохо. Проблемы?


Да, такие тесты пишутся на том, что знает тот, кто их пишет. Обычно это скриптовые языки вроде руби или питон, которые позволяют быстро и просто написать подобного рода вещь. Однако, иногда можно наткнуться на ворох баш-скриптов, Си или что-то более экзотическое (я потратил неделю, переписывая велосипед на баш скриптах на питон, потому что скрипты уже были не расширяемыми и никто толком не знал как они работают и что тестируют).
Пример проекта здесь


Плюсы:


  • автоматизация

Минусы:


  • возможны дополнительные требования к квалификации разработчиков (если они разрабатывают на Java, а тесты были написаны на Python)
  • написание кода для тестирование написаного кода (кто будет тестировать тесты?)

Есть что-нибудь готовое?


Конечно, достаточно посмотреть в сторону BDD. Есть Cucumber, есть Gauge.


Если кратко – разработчик описывает бизнес сценарий на специальном языке, после реализует шаги сценария в коде. Язык как правило человекочитаемый и предполагается что его будут читать/писать не только разработчики, но и менеджеры проектов.


Сценарии вместе с реализацией шагов также находятся в отдельном проекте и запускаются сторонними продуктами (Cucumber/Gauge/…).


Сценарий выглядит так:


Customer sign-up
================

* Go to sign up page

Customer sign-up
----------------
tags: sign-up, customer

* Sign up a new customer with name "John" email "jdoe@test.de" and "password"
* Check if the sign up was successful

И реализация:


@Step("Sign up as <customer> with email <test@example.com> and <password>")
    public void signUp(String customer, String email, String password) {
        WebDriver webDriver = Driver.webDriver;
        WebElement form = webDriver.findElement(By.id("new_user"));
        form.findElement(By.name("user[username]")).sendKeys(customer);
        form.findElement(By.name("user[email]")).sendKeys(email);
        form.findElement(By.name("user[password]")).sendKeys(password);
        form.findElement(By.name("user[password_confirmation]")).sendKeys(password);
        form.findElement(By.name("commit")).click();
    }

    @Step("Check if the sign up was successful")
    public void checkSignUpSuccessful() {
        WebDriver webDriver = Driver.webDriver;
        WebElement message = webDriver.findElements(By.className("message"));
        assertThat(message.getText(), is("You have been signed up successfully!"));
    }

Полный проект здесь


Плюсы:


  • бизнес-логика описана человекочитаемым языком и хранится в одном месте (можно использовать как документацию)
  • используются готовые решения, разработчикам нужно только знать, как их использовать

Минусы:


  • менеджеры не будут читать и писать сценарии
  • приходится следить как за спецификациями, так и за их реализацией (а это и написание кода и правка спецификаций)

Ну и зачем тогда Catcher?


Разумеется, чтобы упростить процесс.


Разработчик пишет только сценарии в json/yaml, а Catcher их выполняет. Сценарий состоит из последовательно выполняемых шагов, например:


steps:
    - http:
        post:
          url: '127.0.0.1/save_data'
          body: {key: '1', data: 'foo'}
    - postgres:
        request:
          conf: 'dbname=test user=test host=localhost password=test'
          query: 'select * from test where id=1'

Catcher поддерживает jinja2 шаблоны, так что можно использовать переменные вместо зашитых значений в примере выше. Глобальные переменные можно хранить в инвентарных файлах (как в ансибле), подтягивать из окружения и регистрировать новые:


variables:
  bonus: 5000
  initial_value: 1000
steps:
- http:
        post:
          url: '{{ user_service }}/sign_up'
          body: {username: 'test_user_{{ RANDOM_INT }}', data: 'stub'}
        register: {user_id: '{{ OUTPUT.uuid }}'
- kafka:
        consume:
            server: '{{ kafka }}'
            topic: '{{ new_users_topic }}'
            where:
                equals: {the: '{{ MESSAGE.uuid }}', is: '{{ user_id }}'}
        register: {balance: '{{ OUTPUT.initial_balance }}'}

Дополнительно можно запускать проверочные шаги:


- check: # check user’s initial balance
    equals: {the: '{{ balance }}', is: '{{ initial_value + bonus }}'}

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


include:
    file: register_user.yaml
    as: sign_up
steps:
    # .... some steps
    - run:
        include: sign_up
    # .... some steps

Вставка и использование скриптов могут решить проблему ожидания ресурса (ждать сервис, пока он стартует).


Помимо готовых встроенные шагов и дополнительного репозитория) есть возможность писать свои модули на питоне (просто наследуя ExternalStep) или на любом другом языке:


#!/bin/bash
one=$(echo ${1} | jq -r '.add.the')
two=$(echo ${1} | jq -r '.add.to')
echo $((${one} + ${two}))

и использование:


---
variables:
  one: 1
  two: 2
steps:
    - math:
        add: {the: '{{ one }}', to: '{{ two }}'}
        register: {sum: '{{ OUTPUT }}'}

Сценарии помещаются в докер файл и запускается через CI.


Также этот образ может быть использован в Marathon/K8s для тестирования существующего окружения. На данный момент я работаю над бэкэндом (аналог AnsibleTower), чтобы сделать процесс тестирования еще проще и удобнее.


Плюсы:


  • не нужно писать код (только в случае кастомных модулей)
  • переключение окружений через инвентарные файлы (как в ансибле)
  • можно использовать собственные модули (на любом языке, даже sh)

Минусы:


  • не человекочитаемый синтаксис (по сравнению с BDD-инструментами)

Вместо заключения


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


Однако инструмент получился гибче, чем я предполагал. Если кого-то заинтересует статья (или сам инструмент), я могу рассказать, как использовать Catcher для организации централизованных миграций и обновления системы микросервисов.


Upd


Как мне указали в комментариях, тема не раскрыта.
Попытаюсь указать здесь наиболее спорные тезисы.


  • end-to-end тесты это не юнит тесты. Я уже ссылался на М.Фаулера в этой статье. Юнит тесты находятся в проекте тестируемого бэкэнда (стандартная директория tests) и запускаются каждый раз при изменении кода на CI. А e2e тесты это отдельный проект, они обычно выполняются дольше, тестируют взаимодествие всех участвующих сервисов и не знают ничего о коде вашего проекта (черный ящик).
  • не стоит использовать Catcher для интеграционных (и ниже) тестов. Это дорого. Гораздо быстрее написать тест на вашем ЯП для текущего бэкэнда. End-to-end тесты вам нужны только если ваша бизнес-логика размазана на 2 и более сервиса.
  • Catcher это тоже BDD. С моей точки зрения, основное преимущество перед Gauge/Cucumber — это готовые модули и легкость их добавления. В идеале пишется только тест. В последней компании я написал все 4 теста на стандартных компонентах, ничего не программируя. Соответственно, требования к квалификации (и цена такого специалиста) будут ниже. Необходимо только знание json/yaml и умение читать спецификации.
  • Для написания Catcher тестов придется изучить Catcher-DSL. Увы, это правда. Я вначале хотел сделать так, чтобы тесты писались сами, прямо с микрофона. Но потом подумал что меня тогда уволят за ненадобностью ;) Как уже было сказано выше — Catcher DSL это стандартный json/yaml и спецификации шагов. Ничего принципиально нового.
  • Вы можете использовать стандартные технологии и написать что-то свое. Однако, мы говорим о микросервисах. Это большое количество разных технологий и ЯП и большое количество команд. И если для ява-команды junit + testcontainers будет очевидным выбором, erlang команда выберет что-то другое. В большой компании при 30+ командах наверху примут решение, что все тесты нужно отдать в новую команду infrastructure/qa. Предствляете, как они обрадуются этому зоопарку?
  • Если у вас 4-5 e2e тестов, то вы можете написать все на любом скриптовом языке и забыть об этом. Однако, если с течением времени логика будет меняться, то через 2-4 года вам придется проводить рефакторинг, разнося непосредственно бизнес-логику тестов и реализацию методов доступа к тестируемым компонентам. Значит в итоге вы напишете свой Catcher, просто не такой гибкий. У меня ушло 4 реализации чтобы это понять ;)

Комментарии (20)


  1. DeusModus
    09.01.2019 00:19

    А в чем все-таки преимущество вашего решения перед BDD?
    Ваши сценарии менеджеры тоже не будут и читать и писать и также придется следить за спецификациями и реализациями.
    По-моему тема «Ну и зачем тогда Catcher?» не раскрыта.


    1. ivanych
      09.01.2019 01:07

      Да это и есть BDD, просто в комплекте идёт некоторое количество готовых определений шагов.


      1. com_tihon Автор
        09.01.2019 12:17

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


  1. neenik
    09.01.2019 00:42

    Да я же джва года такую штуку ждал!
    Её вполне себе можно и для интеграционных тестов применять.
    Самое близкое по идеологии что есть, на мой взгляд — только Postman.
    Ещё в стандартные модули нужен модуль «сервер», который поднимает сервер, ждёт какую-либо нотификацию и её проверяет.


  1. 24twelve
    09.01.2019 06:59

    Спасибо за интересную статью.
    Пара вопросов:
    1. Сколько сейчас у вас есть тестов, использующих Catcher?
    2. Верно ли, что все члены вашей команды пишут end-to-end тесты на этом инструменте?
    3. Как давно вы применяете этот инструмент?
    4. Минус `возможны дополнительные требования к квалификации разработчиков` никуда не делся. Теперь им требуется квалификация в использовании Catcher.
    5. Сложилось ощущение, что вы заново реализуете логику запуска тестов (все эти сетапы, тирдауны...) и логику ассертов. Это действительно нужно? Я не знаю, что там в экосистеме Питона. Но, кажется, должно быть что-то готовое. (PyUnit?)


    1. com_tihon Автор
      09.01.2019 12:07

      1. в текущей компании 2 интеграционных теста, которые проверяют взаимодействие 5и сервисов (не так много тестировать). В предыдущей было 3-4 теста (я только начал применять там этот инструмент) для проверки взаимодействия 10+ сервисов.
      2. мы используем только этот инструмент для e2e, однако он не включает проверку фронтенда (на данный момент у нас нет нормальных тестов для фронтенда). Также не стоит путать юнит/интеграционные тесты и е2е. Все разработчики пишут юнит/интеграционные тесты, каждый стандартную технологию своего ЯП (pyunit/pytest/junit/eunit...). Но только избранные пишут е2е тесты, т.к. это трудоемкий процесс, требующий понимания всей бизнес-логики.
      3. использую этот инструмент уже около года, с тех пор как он появился.
      4. да, требуется знание DSL кэтчера. Однако, он не привязан к какому-либо ЯП и по сути это просто стандартный yaml/json + спецификации шагов. Я специально сделал кэтчер простым и расширяемым. Свой первый тест можно написать за несколько минут.
      5. не путайте е2е и интеграционные тесты. Вторые находятся непосредственно в бэкэнде и реализуются на стандартных технологиях для своего ЯП, с ассертом и моками. Запускаются на пул реквест при изменении этого бэкэнда и ничего не знают о зависимых сервисах (только моки). е2е же запускается сам по себе, обычно после деплоя на дев, либо по таймеру периодически и проверяет все сервисы в системе. Он изолирован от кода и тестирует API по принципу черного ящика.


      1. 24twelve
        09.01.2019 12:35

        Про 4 и 5.
        Я вроде не путаю e2e и интеграционные тесты :)
        Это я к чему написал. Верно ли, что разработать DSL, степы и логику работы с ними было оправданнее, чем просто написать эту логику на питоне? Тем более, если тестов немного (3-4, как вы пишете).


        1. com_tihon Автор
          09.01.2019 12:44

          3-4 теста быстрее написать на любом скриптовом ЯП. Однако, через несколько лет к этим тестам добавятся еще тесты.
          А еще через несколько лет в коде будет мешанина из-за бизнес логики тестов и реализации шагов (в 2ух компаниях уже на такое натыкался). И по итогу будет рефакторинг всего велосипеда, для разделения бизнес логики (увеличение читаемости и поддерживаемости самих тестов) и реализации доступа к сервисам/базам/другим компонентам.
          Вот я и подумал, хочу ли я каждый раз изобретать кэтчер. Всего 4 таких тулза и я понял, что лучше что-то сделать 1 раз, чем каждый раз писать с 0.
          Ну и польза для других опять таки. У меня сейчас 3-4 теста, а у кого-то, может, под 40.


      1. neenik
        09.01.2019 12:37

        На мой взгляд, вы в п.5 ошиблись насчёт интеграционных тестов (вероятно, имелись в виду юнит-тесты). e2e тесты и интеграционные — суть одно и то же, только e2e ближе к пользователю, а интеграционные — к бекенду. Интеграционные они так и называются, что тестируют интеграцию компонентов, а не один компонент с моками.


        1. com_tihon Автор
          09.01.2019 12:57

          У Фаулера хорошо описаны типы тестов. Вот здесь про интеграционные.
          На практике, я не использую все те тесты, что он описал, т.к. не вижу смысла. Они часто друг друга дублируют, что не есть хорошо.
          Обычно у меня есть:


          • юнит тесты. Проверяют отдельные сложные алгоритмы (математика и т.п.). Обычно их мало.
          • функциональные тесты. Проверяют какую-либо бизнес-функцию отдельного сервиса (на service-layer). Все другие сервисы, база данных и внешние сервисы замоккированы.
          • интеграционные тесты. Проверяют всю бизнес-логику по принципу черного ящика без моков базы данных и service layer. Внешние зависимости все еще замоккированы. Можно относиться к ним, как к Controller тестам с реальным service layer и базой данных, но заглушками для внешних сервисов, если мы говорим об http-бэкэндах
          • end-to-end тесты. Проверяют основную бизнес логику вместе со всеми зависимыми сервисами.

          Первые 3 запускаются при изменении кода и локально. Для запуска им особо ничего не нужно (интеграционным нужна база данных/кеш, CI запускает через docker-compose).


          Последние обычно запускаются на тестовом окружении (либо полностью поднимая все окружение в docker-compose, что может быть нереально) и им нужны все сервисы, задействованные в тесте (это главное отличие от интеграционных). Их время выполнения намного превышает все предыдущие вместе взятые.


          1. neenik
            09.01.2019 15:17

            Я с вам не согласен. У вас корректное описание интеграционных тестов, но некорректный вывод, что для интеграционных тестов не нужны все сервисы. Почему не нужны? Интеграционные тесты так же проводятся на все сервисы. У них и название такое «интеграционные» — проверятся интеграция между сервисами.

            Отличие интеграционных и e2e в том, что у e2e нет mock внешних сервисов, а у интеграционных — есть.
            Возможно, мы с вами друг друга не понимаем ещё и потому, что интеграционные тесты можно проводить не только для какой-то подсистемы с набором микросервисов, но и интеграционные высшего уровня — интеграция между этими подсистемами.

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


  1. Frank59
    09.01.2019 11:12

    В целом e2e тестов микросервисов вполне себе подходят обычные либы для юнит-тестирования аля junit + либа для запуска окружения в докере. для джава это, например, testcontainers. Либо уже действительно BDD и cucmber, если нужна человекочитаемость. Велосипедостроение — это всегда хорошо и похвально. Но насчет того, чем данная штука лучше уже существующих решений и почему вы не взяли их, тема не раскрыта.


    1. com_tihon Автор
      09.01.2019 13:29

      Надеюсь что я ответил на ваш вопрос в хвосте статьи (см. обновление).


  1. freezlite
    09.01.2019 11:52

    Чем это отличается от скриптового ЯП?


    1. com_tihon Автор
      09.01.2019 12:13

      Можно без проблем реализовать все интеграционные тесты на питоне\руби\баш. Я описал этот вариант в статье.
      Разница в том, что:
      * DSL кэтчера — это стандартный json/yaml, который знает большинство.
      * Тестируемая логика не зашита в сам инструмент тестирования. По моему опыту, года через 4 скриптовой ЯП с тестами будет напоминать кашу бизнес логики и реализации шагов (драйверы доступа к базам, очередям, хранилищам). И разработчик так или иначе попытается отделить реализацию от бизнес логики. Т.о. каждый, кто начнет со скриптового ЯП в итоге закончит своим собственным кэтчером.


      1. freezlite
        09.01.2019 13:40

        Знает большинство, это как python знает большинство )


  1. savva_genchevskiy
    09.01.2019 13:30

    Не плохое решение для контрактных тестов… В конце статьи описывалось что такой инструмент был создан на определенном проекте и в определенных условиях, чтобы минимизировать количество кода… Я думаю надо было бы больше описать ваш частный случай или условия — по пунктам, при которых инженеры могли
    бы его использовать.
    А еще я вам предлагаю подщаманить его, написать небольшой парсер, или еще небольшую часть фреймворка, чтобы указывая путь на swagger.yaml он мог парсить подобные файлы и делать проверки на данные эндполинты которые описаны в таком формате:
    schemes:
    - "https"
    - "http"
    paths:
    /pet:
    post:
    tags:
    - "pet"
    summary: "Add a new pet to the store"
    description: ""
    operationId: "addPet"
    consumes:
    - "application/json"
    - "application/xml"
    produces:
    - "application/xml"
    - "application/json"
    parameters:
    - in: "body"
    name: "body"
    description: "Pet object that needs to be added to the store"
    required: true
    schema:
    $ref: "#/definitions/Pet"
    responses:
    405:
    description: "Invalid input"
    security:
    - petstore_auth:
    - "write:pets"
    - "read:pets"
    put:
    tags:
    - "pet"
    summary: "Update an existing pet"
    description: ""
    operationId: "updatePet"
    consumes:
    - "application/json"
    - "application/xml"
    produces:
    - "application/xml"
    - "application/json"
    parameters:
    - in: "body"
    name: "body"
    description: "Pet object that needs to be added to the store"
    required: true
    schema:
    $ref: "#/definitions/Pet"
    responses:
    400:
    description: "Invalid ID supplied"
    404:
    description: "Pet not found"
    405:
    description: "Validation exception"
    security:
    - petstore_auth:
    - "write:pets"
    - "read:pets"


    Тогда многие бы точно двинулись пользоваться им, и работа фреймворка была бы похожа больше на магию!)) Как идейка!)


    1. com_tihon Автор
      09.01.2019 13:33

      У вас съехал синтаксис.
      Идея хорошая.
      Я поставлю ее в очередь. Не вижу ничего сложного в автогенерации тестов для вашего случая.
      На данный момент я работаю над Web-UI для упрощения отладки и интеграции с CI.
      Спасибо.


  1. vkirilichev
    09.01.2019 14:35

    Интересно, но из статьи не очень понятно, что же в итоге выйдет протестировать.

    Возьмем ваш проект, после регистрации пользователя почти в каждом из микросервисов должно же что-то произойти, где-то должны записаться данные в базу, где-то должен быть вызван внешний сервис, где-то отправлено сообщение в MQ, где то письмо и т.д. причем наверняка асинхронно. Как это все проверять непонятно, все эти микросервисы наружу таких API не представляют и представлять не должны. А проверка, что сервис ответил 2xx дает лишь ложную уверенность в протестированности.


    1. com_tihon Автор
      09.01.2019 15:19
      +1

      Можно протестировать всю систему.
      Разумеется каждый сервис в цепи задействованных сервисов изменяет данные по результатам своей работы (база/MQ/ftp/письмо). Catcher позволяет проверить любое изменение в базе данных или очереди сообщений с помощью соответствующих модулей.


      В моем проекте на определенные запросы регистрации REST бэкэнд меняет данные в базе и/или посылает сообщения в кафку. Далее сервисы, которые подписаны на этот топик, получают сообщение, делают свои черные дела и пишут данные в базу/ftp/в другой топик. Третьи сервисы получают данные от вторых сервисов и опять что-то делают...


      В регистрационном тесте по сообщениям в кафке и данным в базах я проверяю:


      • Были ли задействаны все необходимые сервисы?
      • Был ли пользователь реально зарегистрирован, или просто вернулось 200, а банковский счет не создался.
      • Был ли порядок обработки сообщений правильным или кто-то опять перепутал топики.
      • Правильно ли сервисы работают с данными, совместимы ли версии и схемы.
        Все происходит асинхронно. Но для теста разницы нет. Мы последовательно проверяем выполнение бизнес логики. От начала регистрации до открытия банковского счета и посылки письма пользователю.

      Вот тут описан пример такого теста для IOT сервисов. А тут реализован е2е тест с Travis интеграцией.