背景:网上有不少介绍这种测试方法的概念和原理的文章,但实现的比较少。本文通过自己的方法从零开始搭建工程,实现了一个例子。在此也感谢朋友的帮助,是参考了TA的代码才能入了这道门。
环境:JDK1.8 + Gradle4.6 + Postgres9.6 + pact_broker
步骤:
这里接上一篇的步骤。契约测试(二)-- 代码实现篇(上)
四、建立Consumer。Consumer中包括两个部分,一部分是定义自身需要的字段,另一部分是测试代码。
1. main->java->prduct_demo中有三个文件。
- Product.java:定义Consumer端需要的数据类型。为了简化这里取名与Provider端相同,返回的数据类型字段定义也与Provider端相同。
- ProductRestFetcher.java:获取数据。
- Application.java:启动入口。
1)Product.java。与上一篇中Provider端的代码相同,这里不再赘述。
2)ProductFetcher.java
package product_demo;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
@Component
public class ProductRestFetcher{
public Product getProductInfo(URI providerUri) {
RestTemplate restTemplate = new RestTemplate();
return (Product)restTemplate.getForOjbect(providerUri, Product.class);
}
}
3) Application.java。同Provider中Application.java,此处不再赘述。
2. test->java->product_demo中写测试文件。这里介绍了两种实现方式。
1)PactBaseConsumerTest.java
package product_demo;
import au.com.dius.pact.consumer.ConsumerPactTestMk2;
import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.Pact;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.model.RequestResponsePact;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PactBaseConsumerTest extends ConsumerPactTestMk2{
@Override
@Pact(provider = "Provider", consumer = "Consumer")
public RequestResponsePact createPact(PactDslWithProvider builder){
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json;charset=UTF-8");
return builder
.given("")
.uponReceiving("My First Pact")
.path("/api/v1/test")
.query("")
.method("GET")
.willRespondWith()
.headers(headers)
.status(200)
.body("{" +
"\"code\": \"product.0\"," +
"\"httpCode\": 200," +
"\"msg\": \"ok\"," +
"\"status\": true\n" +
"}")
.toPact();
}
@Override
protected String providerName(){ return "Provider"; }
@Override
protected String consumerName(){ return "Consumer"; }
@Override
protected void runTest(MockServer mockServer) throws IOException{
String url = mockServer.getUrl();
URI productInfoUri = URI.create(String.format("%s%s", url, "/api/v1/test"));
ProductRestFetcher productRestFetcher = new ProductRestFetcher();
Product product = productRestFetcher.getProdcutInfo(productInfoUri);
assertEquals("product.0", product.getCode());
}
}
2)PactJunitDSLJsonBodyTest.java
package product_demo;
import au.com.dius.pact.consumer.ConsumerPactBuilder;
import au.com.dius.pact.consumer.PactVerificationResult;
import au.com.dius.pact.consumer.dsl.DslPart;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.model.MockProviderConfig;
import au.com.dius.pact.model.PactSpecVersion;
import au.com.dius.pact.model.RequestResponsePact;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import static au.com.dius.pact.consumer.ConsumerPactRunnerKt.runConsumerTest;
import static org.junit.Assert.assertEquals;
public class PactJunitDSLJsonBodyTest{
private void checkResult(PactVerificationResult result){
if (result instanceof PactVerificationResult.Error) {
throw new RuntimeException(((PactVerificationResult.Error)result).getError());
}
assertEquals(PactVerificationResult.Ok.INSTANCE, result);
}
@Test
public void testWithPactDSLJsonBody() {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json;charset=UTF-8");
DslPart body = new PactDslJsonBody()
.stringType("code", "product.0")
.numberType("httpCode", 200)
.stringType("msg", "ok")
.booleanType("status", true)
.close();
}
RequestResponsePact pact = ConsumerPactBuilder
.consumer("JunitDSLJsonBodyConsumer")
.hasPactWith("Provider")
.given("")
.uponReceiving("My First Pact Test")
.path("/api/v1/test")
.query("")
.method("GET")
.willRespondWith()
.headers(headers)
.status(200)
.body(body)
.toPact();
MockProviderConfig config = MockProviderConfig.createDefault(PactSpecVersion.V3);
PactVerificationResult result = runConsumerTest(pact, config, mockServer -> {
String url = mockServer.getUrl();
URI productInfoUri = URI.create(String.format("%s%s", url, "/api/v1/test"));
Product product = new ProductRestFetcher().getProductInfo(productInfoUri);
assertEquals("product.0", product.getCode());
});
checkResult(result);
}
}
五、配置Consumer中的build.gradle文件。
... // 头部省略
buildscript {
repositories {
mavenCentral() // maven仓库
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.8.RELEASE") // gradle插件
classpath("org.thymeleaf:thymeleaf:3.0.8.RELEASE") // springboot工程的starter之一
classpath("au.com.dius:pact-jvm-provider-gradle_2.12:3.5.10") // provider插件
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'au.com.dius.pact'
jar {
baseName = 'Consumer'
version = '1.0.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
test{
systemProperties['pact.rootDir'] = "$rootDir/target/pacts"
}
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-devtools")
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile group: 'junit', name: 'junit', version: '4.1.2'
testCompile("au.com.dius:pact-jvm-consumer-junit_2.12:3.5.12")
testCompile("au.com.dius:pact-jvm-consumer-java8_2.12:3.5.12")
}
pact { // 定义pact,固定格式
publish{ // 定义pact,固定格式
pactDirectory = "$rootDir/target/pacts"
}
}
到此,Provider和Consumer端的代码和配置都完成了,下一篇将介绍测试的过程。
参考资料:
2. https://www.jianshu.com/p/681047496728