自己一直用wiremock的standalone版本,代码中使用的时候就简单封装了http请求来使用,后来看了一下wiremock自己的client使用起来也不错,也支持远端访问,于是推荐给大家
使用本地wiremock
一个stub的demo
- 首先在pom中加好dependency
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.56</version>
<!-- Include everything below here if you have dependency conflicts -->
<classifier>standalone</classifier>
<exclusions>
<exclusion>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
</exclusion>
<exclusion>
<groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId>
</exclusion>
<exclusion>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
- 在java文件中需要导入wiremocker的server、client、config这三个类
import com.github.tomakehurst.wiremock.WireMockServer; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
- 然后这里是testNg的demo
1 @BeforeClass 2 public void setUp() throws FileNotFoundException, IOException 3 { 4 //配置本地端口 5 WireMock.configureFor(9090); 6 wireMockServer = new WireMockServer(wireMockConfig().port(9090)); 7 log.info("START WIREMOCK"); 8 //启动 9 wireMockServer.start(); 10 } 11 12 @AfterClass 13 public void tearDown() throws FileNotFoundException, IOException 14 { 15 //停掉mock 16 wireMockServer.stop(); 17 } 18 19 20 @Test 21 public void testForMock() 22 { 23 24 //配置rule 25 stubFor(post(urlEqualTo("/api/add")) 26 .willReturn(aResponse().withStatus(200).withBody("hzmali"))); 27 //自己写的post方法 28 String response=HttpUtil.post("http://127.0.0.1:9090/api/add",""); 29 log.info("GET RESP:"+response); 30 //检查 31 Assert.assertTrue(response.contains("hzmali")); 32 33 34 } 35 }
结果成功,日志正常
[INFO ]11:52:54, [Class]MockCliTest, [Method]setUp, START WIREMOCK [INFO ]11:52:54, [Class]MockCliTest, [Method]testForMock, GET RESP:hzmali PASSED: testForMock
这里的rule设置
stubFor(post(urlEqualTo("/api/add"))
.willReturn(aResponse().withStatus(200).withBody("hzmali")));
等效于通常的json配置
"requestt" : { "url" : "/api/add", "method" : "POST" }, "response" : { "status" : 200, "body" : "hzmali" }
更多高级stub规则如:
URL的正则匹配:
stubFor(put(urlMatching("/thing/matching/[0-9]+")) .willReturn(aResponse().withStatus(200))); stubFor(put(urlMatching("/thing/matching/.*")) .willReturn(aResponse().withStatus(200)));
REQUEST的header和body的匹配
stubFor(post(urlEqualTo("/with/headers")) .withHeader("Content-Type", equalTo("text/xml")) .withHeader("Accept", matching("text/.*")) .withHeader("etag", notMatching("abcd.*")) .withHeader("X-Custom-Header", containing("2134")) .willReturn(aResponse().withStatus(200))); stubFor(post(urlEqualTo("/with/json/body")) .withRequestBody(equalToJson("{ "houseNumber": 4, "postcode": "N1 1ZZ" }")) .willReturn(aResponse().withStatus(200)));
更多的stub匹配参数,指定返回文件等查看官方手册stub
访问远端wiremock
单元测试一般就像上述的那样起一个本地的wiremock去进行mock,接口测试时的wiremock一般建在另外机器上,所以在自动化接口测试时,跟本地调用有所区别
在上面demo的基础上进行修改,只需要告诉client这个mock在哪
WireMock.configureFor(“192.168.231.131”, 8080);
不需要去创建本地的wiremock,发送请求的地址当然也要改成和目的wiremock一致
1 @BeforeClass 2 public void setUp() throws FileNotFoundException, IOException 3 { 4 WireMock.configureFor("192.168.231.131", 8080); 5 //wireMockServer = new WireMockServer(wireMockConfig()); 6 //log.info("START WIREMOCK"); 7 //wireMockServer.start(); 8 } 9 10 @AfterClass 11 public void tearDown() throws FileNotFoundException, IOException 12 { 13 //wireMockServer.stop(); 14 }
wiremock日志中也看出是有设置rule并匹配上了
2015-07-11 12:39:06.438 Received request to /mappings/new with body { "request" : { "url" : "/api/add", "method" : "POST" }, "response" : { "status" : 200, "body" : "hzmali" } } 2015-07-11 12:39:06.519 Received request: POST /api/add HTTP/1.1 User-Agent: Jakarta Commons-HttpClient/3.0.1 Host: 192.168.231.131:8080 Content-Length: 0 2015-07-11 12:39:06.519 Request received: POST /api/add HTTP/1.1 User-Agent: Jakarta Commons-HttpClient/3.0.1 Host: 192.168.231.131:8080 Content-Length: 0
后记
最新的wiremock官方主页上很良心的推荐了一些同类mock工具
-
Betamax:得配合Junit使用,注解的风格,无standalone版本无爱,页面太花哨看了一会就关了
-
REST-driver:主要用来测试restful 客户端和服务,所以分为client-driver,server-driver,主要用于单测
,其中server-driver封装了restful的请求和响应,拿来做接口测试的请求发送工具也很适合 -
Moco:一个可以轻松搭建测试服务器的框架/工具/程序库,支持socket,国人写的,语法和命令都很简洁
-
MockServer:功能比wiremock强大一圈,支持的功能和调用方式这些工具中最多的,支持maven、java api、standalone、node.js、docker镜像等方式的使用。
其中比较特色的功能如下:
MockServer will play expectations in the exact order they are setup. For example, if an expectation A is setup to response (or forward) 3 times then expectation B is setup to response (or forward) 2 times for the same request MockServer will response (or forward) in the following order A, A, A, B, B.
感受了一下,对于某些场景(比如某个内部逻辑是需要触发失败重试或重连),需要第一次调用A接口返回异常,第二次调用A接口返回正常,对于调用方来说因内部调用接口的情况对外是不可见的,一般让第一次返回失败是很easy的,但没有什么好办法控制什么时候让第二次返回异常,那么MockServer这个按时序返回就很屌炸天了,有空研究一下