Одним из основных аспектов архитектуры микросервисов является то, что приложение формируется как набор слабо связанных сервисов, каждый из которых может быть развернут независимо и связываться друг с другом с помощью некоторого легкого протокола.
Это связано с тем, что архитектура микросервисов — это распределенная система, которая затрудняет написание сквозных тестов. Предположим следующий простой пример, предоставленный Red Hat в качестве примера архитектуры микросервисов ( https://github.com/jbossdemocentral/coolstore-microservice ):
Теперь предположим, что вы хотите написать сквозной тест для службы корзины . Вы быстро увидите, что это совсем не просто, позвольте мне перечислить некоторые из причин:
- Служба Cart должна знать, как загрузить службу ценообразования, службу каталогов и MongoDB (и если вы хотите задействовать внешний интерфейс, а также Coolstore GW и WebUI ).
- Служба корзины должна подготовить некоторые данные (данные) для обеих внешних служб.
- Вы общаетесь со службами, используя сеть. Может случиться, что некоторые тесты не пройдут не из-за реального сбоя, а из-за проблемы инфраструктуры или из-за ошибки других служб. Таким образом, вероятность того, что эти тесты станут ненадежными и начнут давать сбои, не потому, что любые изменения, внесенные в текущую службу, выше.
- В более сложных случаях выполнение этих тестов может быть дорогим с точки зрения стоимости (развертывание в облаке), времени (загрузка всей инфраструктуры и сервисов) и времени обслуживания.
- Сложно запустить их на компьютере разработчика, так как вам нужны все компоненты, установленные на компьютере.
По этой причине сквозные тесты — не лучший подход для тестирования микросервиса, но вам все равно нужен способ тестирования от начала до конца сервиса.
Необходимо найти способ «симулировать» эти внешние зависимости, не вводя какой-либо фиктивный объект. Нам нужно обмануть тестируемый сервис, чтобы он действительно думал, что он взаимодействует с реальными внешними сервисами, а на самом деле это не так.
Метод, который позволяет нам это сделать, — это Service Virtualiztion. Виртуализация служб — это метод, позволяющий имитировать поведение компонентов приложений, таких как API.
Вы можете думать о виртуализации сервисов как о подходе, который вы использовали для реализации в ООП, но вместо симуляции на уровне объекта вы симулируете на уровне сервиса. Это издевательство над предприятием.
Существует множество инструментов виртуализации сервисов, но, по моему опыту, в экосистеме JVM одним из лучших инструментов является Hoverfly .
Давайте посмотрим, как выглядит «сквозной» тест для Cart Service.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "CATALOG_ENDPOINT=catalog")public class CartServiceBoundaryTest { @Autowired private TestRestTemplate restTemplate; @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode(dsl( service("catalog") .get("/api/products") .willReturn(success(json(ProductsObjectMother.createVehicleProducts()))) )); @Test public void should_add_item_to_shopping_cart() { final ShoppingCart shoppingCart = this.restTemplate.postForObject("/api/cart/1/1111/2", "", ShoppingCart.class); assertThat(shoppingCart) .returns(0.0, ShoppingCart::getCartItemPromoSavings) .returns(2000.0, ShoppingCart::getCartItemTotal) .returns(-10.99, ShoppingCart::getShippingPromoSavings) .returns(2000.0, ShoppingCart::getCartTotal) .extracting(ShoppingCart::getShoppingCartItemList) .hasSize(1); }} |
Этот сервис реализован с использованием Spring Boot , поэтому мы используем среду Spring Boot Test. Важной частью здесь является то, что URL, на котором развернута служба каталогов, указывается с помощью
CATALOG_ENDPOINT свойство. И для этого теста он установлен в каталог .
Следующим важным моментом является раздел правил класса Hoverfly. В этом правиле указаны следующие вещи:
- Прокси-сервер Http запускается перед тестированием, и весь исходящий трафик из JVM перенаправляется на этот прокси-сервер.
- Он записывает, что когда запрос к каталогу хоста выполнен и путь к нему равен / api / products, он должен вернуть результат успеха с данным документом json.
Сам тест просто использует TestRestTemplate (это клиент отдыха) и проверяет, что вы можете добавить некоторые элементы в корзину.
Обратите внимание, что вам не нужно настраивать, где запущен прокси-сервер Http, или настраивать любой порт, потому что Hoverfly автоматически настраивает сетевые параметры JVM, поэтому любой сетевой обмен данными осуществляется через прокси-сервер Hoverfly.
Так что обратите внимание, что теперь вам не нужно знать, как загружать службу каталога или как настроить ее с правильными данными.
Вы тестируете весь сервис в его границах, от входящих сообщений до исходящих сообщений другим сервисам, без насмешек над любым внутренним элементом.
Возможно, вы задаетесь вопросом: «Что происходит в случае, если текущий сервис также зависит от сервера базы данных?»
В этом случае вы делаете это как обычно, поскольку сама служба знает, какой сервер баз данных использует и какой тип данных ему требуется, вам нужно только загрузить сервер базы данных, заполнить необходимые данные (фикстуры) и выполнить тесты. Для этого сценария я предлагаю вам использовать Arquillian Cube Docker для загрузки службы базы данных из контейнера Docker, чтобы вам не нужно было устанавливать ее на каждом компьютере, для которого нужно запустить тесты, и Arquillian Persistence Extension для поддержания базы данных в известном состоянии.
В следующем примере сервиса оценки вы можете кратко увидеть, как использовать их для тестов на постоянство:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public class ApueCubeRatingServiceTest { // Starts in local dockerhost (docker machine or native) mongo docker image before running the test class @ClassRule public static ContainerDslRule mongodbContainer = new ContainerDslRule("mongo:3.2.18-jessie") .withPortBinding(27017); //Defines APE (Arquillian Persistence Extension to work as rule) @Rule public ArquillianPersistenceRule arquillianPersistenceRule = new ArquillianPersistenceRule(); // Defines to use MongoDb as NoSql Populator @MongoDb @ArquillianResource NoSqlPopulator populator; @Test public void should_calculate_average_rating_when_adding_an_already_inserted_item() { createPopulatorConfiguration() .usingDataSet("single_rating_with_double.json") .execute(); // Execute test } @After public void tearDown() { createPopulatorConfiguration().clean(); } private NoSqlPopulatorConfigurator createPopulatorConfiguration() { return populator.forServer( mongodbContainer.getIpAddress(), mongodbContainer.getBindPort(27017)) .withStorage(TEST_DATABASE); }} |
При таком подходе вы гарантируете, что все внутренние компоненты службы работают вместе, как и ожидалось, и избегаете беспорядочной природы сквозных тестов в микросервисах.
Таким образом, сквозное тестирование в любом микросервисе — это не то же самое, что сквозное тестирование в монолитном приложении, вы все еще тестируете весь сервис, а просто поддерживаете контролируемую среду, в которой тестирование зависит только от компонентов в пределах границы сервиса. ,
Как контрактные тесты подходят для этого? На самом деле, все, что показано здесь, может быть использовано на стороне клиента и поставщика при тестировании контракта, чтобы избежать необходимости загружать какие-либо внешние сервисы. Таким образом, как утверждают многие авторы, если вы используете контрактные тесты, они становятся новым сквозным тестом.
Вы можете увидеть полные проекты, где оба теста используются здесь и здесь.
Мы продолжаем учиться,
| Опубликовано на Java Code Geeks с разрешения Алекса Сото, партнера нашей программы JCG . См. Оригинальную статью здесь: Написание сквозного теста для архитектуры микросервисов
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |
