最近,我的一位同事偶然发现了Pact.io ,我们的当前应用程序已发展到50多种服务,并且我们开始出现一些集成测试失败和脆弱的开发/验收测试环境。 因此,我们决定研究尝试与此相关的方法。
我从阅读开始: https : //docs.pact.io/faq/convinceme.html
然后观看: https : //www.youtube.com/watch?v = -6x6XBDf9sQ&feature = youtu.be
那两个资源说服了我试一试。
因此,我开始并创建了一组快速的Spring引导应用程序( 此处为GitHub repo),以测试概念并使其正常运行。
突出演示中的一些重要内容。
消费者:
由于Pact是消费者驱动的测试框架。 在这里,您可以定义一个单元测试,该测试模拟http服务器响应,并以此为依据进行断言。
一旦测试成功,它将在/ pacts目录中创建一个pact json文件。
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));
}
}
因此,在运行“模拟”测试并创建协定文件之后。 您需要包括一个maven插件…pact…,然后将其用于将pacts /文件夹的内容发布到pact代理……这在pom中定义如下。
<dependencies>
<!-- https://mvnrepository.com/artifact/au.com.dius/pact-jvm-consumer-junit_2.11 -->
<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>
制片人:
这使用来自Pact.io的JUnit集成从代理下载契约,然后针对正在运行的服务运行。
由于这已经使用了@RunWith批注,因此我无法使用spring bootRunner。 因此,为了解决这个问题,在上课之前,我启动了Spring引导应用程序,然后针对该正在运行的实例运行了协定……并且在测试之后,引导应用程序又被停止了。 根据您的用例,我想也可以使用@Before来执行此操作,这样您就可以在每个软件包之前启动一个新的服务实例,但这会极大地降低执行速度。
@State批注允许客户端定义特定的状态,生产者可以使用该状态来设置测试运行所需的其他数据/条件。
一旦对服务执行了契约,目标文件夹中就会生成报告。
@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();
}
}
设置契约代理
1.从Docker Hub获取公共映像。
docker pull dius/pact_broker
docker pull postgres
2.然后设置Postgres数据库
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.数据库启动后,运行实际的代理:
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
获取示例项目
翻译自: https://www.javacodegeeks.com/2017/03/consumer-driven-testing-pact-spring-boot.html