Недавно мой коллега наткнулся на Pact.io. Наше текущее приложение выросло до более чем 50 сервисов, и мы начинаем испытывать некоторые сбои интеграционных тестов и хрупкую среду разработки / принятия. Поэтому мы решили взглянуть на способы помочь с этим.
Я начал с чтения: https://docs.pact.io/faq/convinceme.html
Тогда смотрите: https://www.youtube.com/watch?v=-6x6XBDf9sQ&feature=youtu.be
Эти 2 ресурса убедили меня дать ему шанс.
Поэтому я разработал и создал быстрый набор загрузочных приложений Spring, репозиторий GitHub, чтобы проверить концепции и заставить все работать.
Чтобы выделить некоторые важные моменты из демонстрации.
Потребитель:
Pact — это ориентированная на потребителя среда тестирования. Здесь вы определяете модульный тест, который проверяет ответ http-сервера, и вы утверждаете против этого.
Как только тест пройден успешно, он создает pact-файл json в каталоге / pacts.
|
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
39
40
|
public class TestProvider { @Rule public PactProviderRule provider = new PactProviderRule("test_provider", "localhost", 8081, this); @Pact(state = "default", provider = "test_provider", consumer = "test_consumer") public PactFragment createFragment(PactDslWithProvider builder) { Map<String, String> headers = new HashMap<>(); headers.put("content-type", "application/json"); return builder .given("default") .uponReceiving("Test User Service") .path("/user/1") .method("GET") .willRespondWith() .status(200) .headers(headers) .body("{" + " \"userName\": \"Bob\",\n" + " \"userId\": \"1\",\n" + " \"firstName\": null,\n" + " \"lastName\": null,\n" + " \"email\": null,\n" + " \"groups\": null\n" + "}") .toFragment(); } @Test @PactVerification("test_provider") public void runTest() throws IOException { final RestTemplate call = new RestTemplate(); final User expectedResponse = new User(); expectedResponse.setUserName("Bob"); expectedResponse.setUserId("1"); final User forEntity = call.getForObject(provider.getConfig().url() + "/user/1", User.class); assertThat(forEntity, sameBeanAs(expectedResponse)); }} |
Таким образом, после запуска теста «mock» и создания файла pact. Вам необходимо включить плагин maven… pact…, который затем используется для публикации содержимого папки / пакта посреднику pact…, который определен в pom, как показано ниже.
|
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
|
<dependencies> <dependency> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-consumer-junit_2.11</artifactId> <version>3.3.6</version> <scope>test</scope> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.18</version> <configuration> <systemPropertyVariables> <pact.rootDir>pacts</pact.rootDir> <buildDirectory>${project.build.directory}</buildDirectory> </systemPropertyVariables> </configuration> </plugin> <plugin> <groupId>au.com.dius</groupId> <artifactId>pact-jvm-provider-maven_2.11</artifactId> <version>3.3.4</version> <configuration> <pactDirectory>pacts</pactDirectory> <projectVersion>1.0.1</projectVersion> </configuration> </plugin> </plugins></build> |
Режиссер:
При этом используется интеграция JUnit из Pact.io для загрузки пактов от брокера и последующего запуска с работающей службой.
Так как здесь уже используется аннотация @RunWith, я не смог использовать бегун с пружинной загрузкой. Таким образом, чтобы обойти это как шаг перед классом, я запускаю загрузочное приложение Spring, затем пакты запускаются для этого запущенного экземпляра … и загрузочное приложение снова останавливается после тестов. В зависимости от вашего варианта использования, я думаю, что это также будет возможность сделать это с @Before, чтобы вы запускали новый экземпляр службы перед каждым пакетом, но это сильно замедляло бы выполнение.
Аннотация @State позволяет клиентам определять определенное состояние, которое производитель может использовать для настройки дополнительных данных / условий, необходимых для выполнения теста.
После того, как договоры выполнены со службой, в целевой папке создаются отчеты.
|
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
|
@RunWith(PactRunner.class)@Provider("test_provider" )@PactBroker(host = "localhost", port = "80")@VerificationReports({"console", "markdown"})public class TestPacts { private static ConfigurableApplicationContext application; @TestTarget public final Target target = new HttpTarget(8080); @BeforeClass public static void startSpring(){ application = SpringApplication.run(ProviderServiceApplication.class); } @State("default") public void toDefaultState() { System.out.println("Now service in default state"); } @State("extra") public void toExtraState() { System.out.println("Now service in extra state"); } @AfterClass public static void kill(){ application.stop(); }} |
Настройка Pact Broker
1. Получите общедоступные изображения из Docker Hub.
|
1
2
|
docker pull dius/pact_brokerdocker pull postgres |
2. Затем настройте Postgres DB
|
1
2
3
4
5
|
docker run --name pactbroker-db -e POSTGRES_PASSWORD=ThePostgresPassword -e POSTGRES_USER=admin -d postgresdocker run -it --link pactbroker-db:postgres --rm postgres psql -h postgres -U adminCREATE USER pactbrokeruser WITH PASSWORD 'TheUserPassword';CREATE DATABASE pactbroker WITH OWNER pactbrokeruser;GRANT ALL PRIVILEGES ON DATABASE pactbroker TO pactbrokeruser; |
3. После запуска БД запустите реальный брокер:
|
1
|
docker run --name pactbroker --link pactbroker-db:postgres -e PACT_BROKER_DATABASE_USERNAME=pactbrokeruser -e PACT_BROKER_DATABASE_PASSWORD=TheUserPassword -e PACT_BROKER_DATABASE_HOST=postgres -e PACT_BROKER_DATABASE_NAME=pactbroker -d -p 80:80 dius/pact_broker |
Дополнительные ссылки:
- https://docs.pact.io/documentation/
- https://docs.pact.io/documentation/sharings_pacts.html
- https://github.com/DiUS/pact-jvm
- https://github.com/DiUS/pact-jvm/tree/master/pact-jvm-consumer-junit
Получить пример проекта
| Ссылка: | Тестирование, ориентированное на потребителя, с помощью Pact & Spring Boot от нашего партнера JCG Брайана Дю Приза в блоге Zen, посвященном искусству ИТ . |