Статьи

Тестирование с помощью Pact & Spring Boot

Недавно мой коллега наткнулся на 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>
                <pactBrokerUrl>http://localhost:80</pactBrokerUrl>
                <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_broker
docker pull postgres

2. Затем настройте Postgres DB

1
2
3
4
5
docker run --name pactbroker-db -e POSTGRES_PASSWORD=ThePostgresPassword -e POSTGRES_USER=admin -d postgres
docker run -it --link pactbroker-db:postgres --rm postgres psql -h postgres -U admin
CREATE 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

Дополнительные ссылки:

Получить пример проекта