WireMock 是一个灵活的库用于 Web 服务測试,和其它測试工具不同的是。WireMock 创建一个实际的 HTTPserver来执行你的 Web 服务以方便測试。

它支持 HTTP 响应存根、请求验证、代理/拦截、记录和回放。 而且能够在单元測试下使用或者部署到測试环境。

它能够用在哪些场景下:

  • 測试移动应用依赖于第三方REST APIs
  • 创建高速原型的APIs
  • 注入否则难于模拟第三方服务中的错误
  • 不论什么单元測试的代码依赖于web服务的
文件夹
前提条件
Maven配置
准备工作
Examples
Troubleshooting
參考

前提条件


  • JDK 1.7
  • Maven 3

Maven配置


pom里加入下面的dependencies

<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.53</version>
<classifier>standalone</classifier>
</dependency>

<dependency>

        <groupId>org.testng</groupId>

        <artifactId>testng</artifactId>

        <version>6.8</version>

  </dependency>

假设有依赖冲突,能够exclued 掉冲突的依赖, 配置例如以下

<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>1.53</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>

准备工作


首先我写了一个类HTTPRequestor用来运行Http request訪问Rest服务的。 然后我须要一个Rest服务来測试我写的类是否ok, 但我手上没有一个真实的Rest web service, 所以WireMock就能够出场了,模拟一个Rest web serivce来測试我这个类。

HTTPRequestor例如以下:

 1 package com.demo.HttpRequestor;
2
3 import static com.jayway.restassured.RestAssured.given;
4
5 import java.util.HashMap;
6 import java.util.Map;
7
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10
11 import com.jayway.restassured.response.Response;
12 import com.jayway.restassured.specification.RequestSpecification;
13
14 /**
15 * Wrapper for RestAssured. Perform an HTTP requests.
16 *
17 * @author wadexu
18 *
19 */
20 public class HTTPRequestor {
21
22 protected static final Logger logger = LoggerFactory.getLogger(HTTPRequestor.class);
23 private RequestSpecification reqSpec;
24
25
26 /**
27 * Constructor. Initializes the RequestSpecification (relaxedHTTPSValidation
28 * avoids certificate errors).
29 *
30 */
31 public HTTPRequestor() {
32 reqSpec = given().relaxedHTTPSValidation();
33 }
34
35 public HTTPRequestor(String proxy) {
36 reqSpec = given().relaxedHTTPSValidation().proxy(proxy);
37 }
38
39 /**
40 * Performs the request using the stored request data and then returns the response
41 *
42 * @param url
43 * @param method
44 * @param headers
45 * @param body
46 * @return response Response, will contain entire response (response string and status code).
47 * @throws Exception
48 */
49 public Response perform_request(String url, String method, HashMap<String, String> headers, String body) throws Exception {
50
51 Response response = null;
52
53 try {
54
55 for(Map.Entry<String, String> entry: headers.entrySet()) {
56 reqSpec.header(entry.getKey(), entry.getValue());
57 }
58
59 switch(method) {
60
61 case "GET": {
62 response = reqSpec.get(url);
63 break;
64 }
65 case "POST": {
66 response = reqSpec.body(body).post(url);
67 break;
68 }
69 case "PUT": {
70 response = reqSpec.body(body).put(url);
71 break;
72 }
73 case "DELETE": {
74 response = reqSpec.delete(url);
75 break;
76 }
77
78 default: {
79 logger.error("Unknown call type: [" + method + "]");
80 }
81 }
82
83 } catch (Exception e) {
84 logger.error("Problem performing request: ", e);
85 }
86
87 return response;
88 }
89 }

这个类是须要依赖 jayway 的 rest-assured包的

        <dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.3.3</version>
<scope>test</scope>
</dependency>

Examples


新建一个測试类HTTPRequestorMockTest

new 一个 WireMockService 配置一下 然后启动

        wireMockServer = new WireMockServer(wireMockConfig().port(8090));
WireMock.configureFor("localhost", 8090);
wireMockServer.start();

在測试方法之前

创建存根, 指明是GET方法,URL路径, Header的内容,会返回什么样的Response

    @BeforeTest
public void stubRequests() {
stubFor(get(urlEqualTo("/cars/Chevy"))
.withHeader("Accept", equalTo("application/json"))
.withHeader("User-Agent", equalTo("Jakarta Commons-HttpClient/3.1"))
.willReturn(aResponse()
.withHeader("content-type", "application/json")
.withStatus(200)
.withBody("{\"message\":\"Chevy car response body\"}")
)
);
}

##转载注明出处: http://www.cnblogs.com/wade-xu/p/4299710.html

一切都模拟好了,接下来開始測试了。測试方法例如以下

@Test
public void test_Get_Method() { String url = "http://localhost:8090/cars/Chevy";
String method = "GET";
String body = ""; HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json");
headers.put("User-Agent", "Jakarta Commons-HttpClient/3.1"); HTTPRequestor httpRequestor = new HTTPRequestor();
Response response = null; try {
response = httpRequestor.perform_request(url, method, headers, body);
} catch (Exception e) {
fail("Problem using HTTPRequestor to generate response: " + e.getMessage());
} assertEquals(200, response.getStatusCode());
assertEquals("Chevy car response body", response.jsonPath().get("message")); }

上面的样例是GET,没有请求体。以下我们来看POST的样例

同理 创建存根

RequestBody如果为"Mini Cooper"

 stubFor(post(urlEqualTo("/cars/Mini"))
.withHeader("Authorization", equalTo("Basic d8d74jf82o929d"))
.withHeader("Accept", equalTo("application/json"))
.withHeader("User-Agent", equalTo("Jakarta Commons-HttpClient/3.1"))
.withRequestBody(equalTo("Mini Cooper"))
.willReturn(aResponse()
.withHeader("content-type", "application/json")
.withStatus(200)
.withBody("{\"message\":\"Mini Cooper car response body\", \"success\":true}")
)
);

測试方法例如以下:

 @Test
public void test_Post_Method() { String url = "http://localhost:8090/cars/Mini";
String method = "POST";
String body = "Mini Cooper"; HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Authorization", "Basic d8d74jf82o929d");
headers.put("Accept", "application/json");
headers.put("User-Agent", "Jakarta Commons-HttpClient/3.1"); HTTPRequestor httpRequestor = new HTTPRequestor();
Response response = null; try {
response = httpRequestor.perform_request(url, method, headers, body);
} catch (Exception e) {
fail("Problem using HTTPRequestor to generate response: " + e.getMessage());
} assertEquals(200, response.getStatusCode());
assertEquals("Mini Cooper car response body", response.jsonPath().get("message"));
assertEquals(true, response.jsonPath().get("success")); }

PUT 和 DELETE 都是一样的道理,有兴趣的读者能够自行练习。

測试结束之后 不要忘记tear down, 停掉WireMockServer

@AfterTest(alwaysRun=true)
public void tearDown() {
wireMockServer.stop();
wireMockServer.shutdown();
}

贴出我的整个測试类 (两个測试方法都须要相同的參数,所以能够用@DataProvider的方式来改进。我这里就不具体阐述了)

1 package com.demo.mocktest;
2
3 import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4 import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
5 import static com.github.tomakehurst.wiremock.client.WireMock.get;
6 import static com.github.tomakehurst.wiremock.client.WireMock.post;
7 import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
8 import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
9 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
10 import static org.testng.Assert.assertEquals;
11 import static org.testng.Assert.fail;
12
13 import java.util.HashMap;
14
15 import org.testng.ITest;
16 import org.testng.annotations.AfterTest;
17 import org.testng.annotations.BeforeTest;
18 import org.testng.annotations.Test;
19
20 import com.demo.HttpRequestor.HTTPRequestor;
21 import com.github.tomakehurst.wiremock.WireMockServer;
22 import com.github.tomakehurst.wiremock.client.WireMock;
23 import com.jayway.restassured.response.Response;
24
25 public class HTTPRequestorMockTest implements ITest{
26
27 private WireMockServer wireMockServer;
28
29 @Override
30 public String getTestName() {
31 return "Mock Test";
32 }
33
34 public HTTPRequestorMockTest() {
35 wireMockServer = new WireMockServer(wireMockConfig().port(8090));
36 WireMock.configureFor("localhost", 8090);
37 wireMockServer.start();
38 }
39
40 @BeforeTest
41 public void stubRequests() {
42 stubFor(get(urlEqualTo("/cars/Chevy"))
43 .withHeader("Accept", equalTo("application/json"))
44 .withHeader("User-Agent", equalTo("Jakarta Commons-HttpClient/3.1"))
45 .willReturn(aResponse()
46 .withHeader("content-type", "application/json")
47 .withStatus(200)
48 .withBody("{\"message\":\"Chevy car response body\"}")
49 )
50 );
51
52 stubFor(post(urlEqualTo("/cars/Mini"))
53 .withHeader("Authorization", equalTo("Basic d8d74jf82o929d"))
54 .withHeader("Accept", equalTo("application/json"))
55 .withHeader("User-Agent", equalTo("Jakarta Commons-HttpClient/3.1"))
56 .withRequestBody(equalTo("Mini Cooper"))
57 .willReturn(aResponse()
58 .withHeader("content-type", "application/json")
59 .withStatus(200)
60 .withBody("{\"message\":\"Mini Cooper car response body\", \"success\":true}")
61 )
62 );
63 }
64
65 @Test
66 public void test_Get_Method() {
67
68 String url = "http://localhost:8090/cars/Chevy";
69 String method = "GET";
70 String body = "";
71
72 HashMap<String, String> headers = new HashMap<String, String>();
73 headers.put("Accept", "application/json");
74 headers.put("User-Agent", "Jakarta Commons-HttpClient/3.1");
75
76
77 HTTPRequestor httpRequestor = new HTTPRequestor();
78 Response response = null;
79
80 try {
81 response = httpRequestor.perform_request(url, method, headers, body);
82 } catch (Exception e) {
83 fail("Problem using HTTPRequestor to generate response: " + e.getMessage());
84 }
85
86 assertEquals(200, response.getStatusCode());
87 assertEquals("Chevy car response body", response.jsonPath().get("message"));
88
89 }
90
91 @Test
92 public void test_Post_Method() {
93
94 String url = "http://localhost:8090/cars/Mini";
95 String method = "POST";
96 String body = "Mini Cooper";
97
98 HashMap<String, String> headers = new HashMap<String, String>();
99 headers.put("Authorization", "Basic d8d74jf82o929d");
100 headers.put("Accept", "application/json");
101 headers.put("User-Agent", "Jakarta Commons-HttpClient/3.1");
102
103 HTTPRequestor httpRequestor = new HTTPRequestor();
104 Response response = null;
105
106 try {
107 response = httpRequestor.perform_request(url, method, headers, body);
108 } catch (Exception e) {
109 fail("Problem using HTTPRequestor to generate response: " + e.getMessage());
110 }
111
112 assertEquals(200, response.getStatusCode());
113 assertEquals("Mini Cooper car response body", response.jsonPath().get("message"));
114 assertEquals(true, response.jsonPath().get("success"));
115
116 }
117
118 @AfterTest(alwaysRun=true)
119 public void tearDown() {
120 wireMockServer.stop();
121 wireMockServer.shutdown();
122 }
123
124 }

##转载注明出处: http://www.cnblogs.com/wade-xu/p/4299710.html

Run as TestNG

測试结果例如以下:

PASSED: Mock Test
PASSED: Mock Test ===============================================
Default test
Tests run: 2, Failures: 0, Skips: 0
=============================================== [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@26b923ee: 7 ms
[TestNG] Time taken by [TestListenerAdapter] Passed:0 Failed:0 Skipped:0]: 1 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter@512f0124: 5 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@5a4ec51c: 7 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@5706937e: 31 ms

Troubleshooting


HTTPRequestor类第59行 报错Cannot switch on a value of type String for source level below 1.7. Only convertible int values or enum constants are permitted

--- Java Build Path 设置 JRE System library 1.7 以上

Static import 例如以下:

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;

參考


官方文档:http://wiremock.org/

本文同一时候发表在博客园 http://www.cnblogs.com/wade-xu/p/4299710.html

玩转单元測试之WireMock -- Web服务模拟器的更多相关文章

  1. 玩转单元测试之WireMock -- Web服务模拟器

    玩转单元测试之WireMock -- Web服务模拟器 WireMock 是一个灵活的库用于 Web 服务测试,和其他测试工具不同的是,WireMock 创建一个实际的 HTTP服务器来运行你的 We ...

  2. 玩转单元測试之DBUnit

    本文同一时候发表在:http://www.cnblogs.com/wade-xu/p/4547381.html DBunit 是一种扩展于JUnit的数据库驱动測试框架,它使数据库在測试过程之间处于一 ...

  3. OpenStack中给wsgi程序写单元測试的方法

    在 OpenStack 中, 针对web应用, 有三种方法来写单元測试 1) 使用webob生成模拟的request from __future__ import print_function imp ...

  4. 聊聊单元測试(一)——EasyMock

    一.单元測试是保证软件质量的重要方法. 单元測试是对系统中某个模块功能的验证,但我们总会遇到这样那样的问题,导致測试代码非常难编写.最直接的一个原因便是强耦合关系,被測试者依赖一些不easy构造,比較 ...

  5. [iOS翻译]《iOS7 by Tutorials》在Xcode 5里使用单元測试(上)

    简单介绍: 单元測试是软件开发的一个重要方面.毕竟,单元測试能够帮你找到bug和崩溃原因,而程序崩溃是Apple在审查时拒绝app上架的首要原因. 单元測试不是万能的,但Apple把它作为开发工具包的 ...

  6. 利用Continuous Testing实现Eclipse环境自己主动单元測试

    当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...

  7. 在Eclipse中使用JUnit4进行单元測试(0基础篇)

    本文绝大部分内容引自这篇文章: http://www.devx.com/Java/Article/31983/0/page/1 我们在编写大型程序的时候,须要写成千上万个方法或函数,这些函数的功能可能 ...

  8. C语言单元測试

    C语言单元測试 对于敏捷开发来说,单元測试不可缺少,对于Java开发来说,JUnit非常好,对于C++开发,也有CPPUnit可供使用,而对于传统的C语言开发,就没有非常好的工具可供使用,能够找到的有 ...

  9. Android单元測试之JUnit

    随着近期几年測试方面的工作慢慢火热起来.常常看见有招聘測试project师的招聘信息.在Java中有单元測试这么一个JUnit 方式,Android眼下主要编写的语言是Java,所以在Android开 ...

随机推荐

  1. CAD交互绘制圆(com接口)

    CAD绘制图像的过程中,画圆的情况是非常常见的,用户可以在控件视区点取任意一点做为圆心,再动态点取半径绘制圆. 主要用到函数说明: _DMxDrawX::DrawCircle 绘制一个圆.详细说明如下 ...

  2. shell 循环 read line

    cat dockerlist |while read line;do docker rmi  $line ;done

  3. python中的next()以及iter()函数

    我们首先要知道什么是可迭代的对象(可以用for循环的对象)Iterable: 一类:list,tuple,dict,set,str 二类:generator,包含生成器和带yield的generato ...

  4. js判断图片是否有效

    var ImgObj=new Image(); ImgObj.src= 'http://192.168.10.6:8082/3D/SERVER_1_DELL_880.jpg'; if(ImgObj.f ...

  5. vue-cli webpack 快速搭建项目

    一.安装vue npm install vue -g 二.用vue-cli快速搭建项目 //全局安装vue-cli npm install install -g vue-cli //创建一个基于web ...

  6. Runlevel in Linux

    运行级别(Runlevel)指的是Unix或者Linux等类Unix操作系统下不同的运行模式.运行级别通常分为7等,分别是从0到6,但如果必要的话也可以更多. 例如在大多数Linux操作系统下一共有如 ...

  7. 源码学习-String类

    最近在扫描CodeDex时报了一个不能使用String.intern()的字符串来做锁对象的告警,对这个问题有疑问查了些资料,顺便学习一下String类的源码. 1.类定义 String 被final ...

  8. assert.fail()详解

    assert.fail(actual, expected, message, operator) 抛出一个 AssertionError.如果 message 是假值,错误信息会被设置为被 opera ...

  9. Broadcasting

    目录 Broadcasting Key idea How to understand? Why broadcasting? Broadcastable? Broadcast VS Tile Broad ...

  10. C语言的移位操作符及位运算

    C语言的移位操作符 位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算.位移位运算符分为左移和右移两种,均为双目运算符.第一运算对象是移位对象,第二个运算对象是所移的二进制位数. 位 ...