`

【转】玩转单元测试之WireMock -- Web服务模拟器

 
阅读更多

WireMock 是一个灵活的库用于 Web 服务测试,和其他测试工具不同的是,WireMock 创建一个实际的 HTTP服务器来运行你的 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 

分享到:
评论

相关推荐

    lede模拟器-openwrt模拟器-malta-mips-be-uClibc.part1.rar

    lede模拟器-openwrt模拟器-malta-mips-be-uClibc.part1.rar,由于文件太大,分成了两个文件上传part1和part2 linux或windows都可以运行,需要安装qemu qemu-system-mips -M malta -hda lede-malta-be-root.ext4 -...

    S7200模拟器.rar_S7 200模拟器.r_S7 模拟器_S7COMM模拟器_plc200模拟器_s7-200

    标题中的"S7200模拟器.rar_S7 200模拟器.r_S7 模拟器_S7COMM模拟器_plc200模拟器_s7-200"指的是一个压缩包文件,包含了用于模拟西门子S7-200 PLC(可编程逻辑控制器)的操作软件。这个模拟器允许用户在没有实际硬件...

    思科超强模拟器 WEB-IOU中文版使用手册

    【思科超强模拟器 WEB-IOU 中文版使用手册】是为网络专业人士提供的一款强大的模拟工具,尤其适合初学者和准备CCNA、CCIE、CCNP等认证考试的学员。WEB-IOU,全称为Web-based IOU(Input/Output Unit),是由思科开发...

    wiremock-standalone-3.3.1 jar包

    WireMock是一个基于HTTP的API模拟器,其核心是web服务。它可以为特定的请求提供固定的返回值,并捕获传入的请求以供后续校验。当依赖的API不存在或不完整时,WireMock可以让您保持高效,通过为测试真实API无法可靠...

    F5-模拟器 F5-模拟器.zip

    标题 "F5-模拟器 F5-模拟器.zip" 提供了一个关于F5技术的模拟器使用的主题,而描述详细地列举了几个关键步骤,包括F5设备的许可证注册、模拟器获取、F5虚拟机的配置以及LTM VE(Local Traffic Manager Virtual ...

    Nebula模拟器-Nebula模拟器-Nebula模拟器

    在实际应用中,Nebula模拟器广泛应用于测试和开发环境,企业可以快速创建和销毁测试环境,无需购买和维护大量硬件。同时,它也适用于大型数据中心,帮助实现资源的动态调度和优化。 在文件名称列表中提到的“Nebula...

    lede模拟器-openwrt模拟器-malta-mips-be-uClibc.part2.rar

    lede模拟器-openwrt模拟器-malta-mips-be-uClibc.part1.rar,由于文件太大,分成了两个文件上传part1和part2 linux或windows都可以运行,需要安装qemu qemu-system-mips -M malta -hda lede-malta-be-root.ext4 -...

    最新思科Cisco CCNP CCIE 模拟器WEB-IOU使用教程

    它是WEB-IOU模拟器运行的平台之一。 3. WEB-IOU模拟器的下载和安装: - WEB-IOU模拟器可以从指定的链接下载,而且需要一定的内存资源分配,推荐2GB或以上。 - 安装虚拟机VMware-workstation,下载并提取WEB-IOU...

    数据采集工具之----------Dtu模拟器

    通过这种模拟器,开发人员和系统管理员可以在不依赖物理硬件的情况下进行测试、调试和配置工作。Dtu模拟器具备模拟通讯设备的基本功能,例如建立连接、断开连接、数据传输以及心跳包的自动发送。心跳包是维持通信...

    genymotion-2.8.1-vbox模拟器+破解补丁.part3

    测试通过 ------------------------------------------------- genymotion-2.8.1-vbox模拟器+破解补丁.rar 文件太大分了3个压缩包 genymotion-2.8.1-vbox模拟器+破解补丁.part1.rar genymotion-2.8.1-vbox模拟器+...

    AS安卓开发-使用外部模拟器-mumu模拟器,调试运行程序

    ### AS安卓开发-使用外部模拟器-mumu模拟器,调试运行程序 在Android开发过程中,除了使用Android Studio自带的模拟器之外,还可以选择其他第三方模拟器来提高开发效率。其中,MuMu模拟器因其良好的性能表现及较低的...

    s7-200模拟器b25c

    这款模拟器主要用于在没有实际硬件的情况下,对S7-200 PLC的程序进行测试和调试,帮助工程师们在设计自动化系统时提高效率,减少现场实验的成本。 【描述分析】 描述中的信息简洁,仅提及了模拟器的名称,暗示这是...

    手机Web模拟器 (OperaMobileEmulator)

    【手机Web模拟器Opera Mobile Emulator】是一款专为移动开发者设计的强大工具,它允许开发者在桌面环境下模拟手机上的Web浏览体验,以便于测试和调试移动Web应用。这款模拟器是Opera公司开发的,旨在提供一个近似...

    人生重开模拟器-小游戏-NAS-WebStation-HTML5

    一旦端口设置正确,你只需在浏览器中输入NAS的IP地址和指定端口号,就可以开始玩《人生重开模拟器》了。 在NAS上运行这款游戏有几点优势。一是安全性,因为数据存储在本地网络中,相比公共服务器,个人信息和数据更...

    fx-991es模拟器

    这款模拟器使得用户可以在电脑上体验与实体 fx-991ES 相同的操作界面和计算功能,为那些需要在不同场合使用或测试该计算器功能的用户提供极大的便利。 Casio 的 fx-991ES 是一款非常流行的科学计算器,尤其在教育...

    PC-YUZU模拟器-4176绝版开源-switch模拟器

    模拟器使用(简单介绍一下原理,免得不清楚原理,就玩游戏,也不知道怎么使用。不想了解原理的,有一键安装包,最后有一键本地安装更新工具) 模拟器包含三个文件 1.模拟器本体 2.系统固件 3.秘钥 4.游戏本体 1、...

    genymotion-2.8.1-vbox模拟器+破解补丁.part2

    测试通过 ------------------------------------------------- genymotion-2.8.1-vbox模拟器+破解补丁.rar 文件太大分了3个压缩包 genymotion-2.8.1-vbox模拟器+破解补丁.part1.rar genymotion-2.8.1-vbox模拟器+...

    genymotion-2.8.1-vbox模拟器+破解补丁.part1

    测试通过 ------------------------------------------------- genymotion-2.8.1-vbox模拟器+破解补丁.rar 文件太大分了3个压缩包 genymotion-2.8.1-vbox模拟器+破解补丁.part1.rar genymotion-2.8.1-vbox模拟器+...

    S7-200 模拟器 V2.0-最新版本的S7 200模拟器.rar

    S7-200模拟器V2.0是一款专为西门子S7-200系列PLC(可编程逻辑控制器)设计的仿真软件,它允许用户在没有实际硬件设备的情况下进行程序开发、调试和测试。这款最新的版本提供了更强大的功能和更优化的用户体验,对于...

    fx-82ES模拟器

    卡西欧fx-82ES模拟器是一款教学用计算器。卡西欧fx-82ES计算器仿真软件,卡西欧fx-82es科学计算器,跟真实计算器用法一模一样,体积小功能齐全,真正的电脑计算器,拥有卡西欧fx-82ES计算器的所有功能,能够满足各种...

Global site tag (gtag.js) - Google Analytics