Web服务模拟器——wiremock

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

其它资料:https://www.cnblogs.com/tanglang/p/4791198.html

 

WireMock是一个开源的测试工具,支持HTTP响应存根、请求验证、代理/拦截、记录和回放。最直接的用法: 

  • 为Web/移动应用构建Mock Service
  • 快速创建Web API原型
  • 模拟Web Service中错误返回
  • 录制HTTP请求和回放

 一般开发项目都会把前端组和Service组分开,或者服务间存在依赖的关系,当进度不一致时,可以根据接口构建Mock Service,模拟不同输入/数据/场景,这样不至于影响两组的开发进度。构建Mock Service方法很多,如:开源工具moco、postman、node.js、soapUI。其中soapUI还可以对Service进行功能/性能测试,功能非常齐全,与soapUI相比,Wiremock好在轻便,一个jar包基本能够满足大多数需求,当然,也可以把它引用写进测试代码里。

通过可执行jar文件单独运行:

1、下载可执行jar文件:http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.13.0/wiremock-standalone-2.13.0.jar

2、通过以下命令运行:

java -jar wiremock-standalone-2.13.0.jar

默认绑定端口是8080

如果我们已经有请求/响应json文件(可以是手动编写也可以是录制生成、修改),可以先把这些文件放在jar文件同一级目录的mappings文件夹中(默认的路径),然后再执行jar文件,当然也可以在执行jar文件时指定到json文件所在的位置

通过命令行参数做更多配置:

--port:设置http端口号,如:--port 9999

--https-port:如果声明该参数,则表示开启HTTPS端口

--root-dir:设置文件根目录,也就是mappings文件夹和__files文件夹所在的位置,其中mappings是请求/响应json文件所在的目录,也是录制生成文件的目录,默认为jar文件所在的当前目录

--record-mappings:设置录制生成文件的目录,默认为jar文件当前目录的mappings文件夹

更多配置请看:http://wiremock.org/docs/running-standalone/

3、启动后,我们便可以访问该HTTP服务器了

例如,端口号为8080,我们手动编写的json文件如下:

{
  "request" : {
    "url" : "/userInfo?name=liming&age=23",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "jsonBody" : {
		"name":"方法方法是是",
		"age" : "13"
	},
    	"headers": {
      		"Content-Type": "application/json ; charset=UTF8"
    	}
  }
}

1)可以通过http://localhost:8080/userInfo?name=liming&age=23来调用模拟的userInfo接口

2)通过http://localhost:8080/__admin/可以看到当前wiremock模拟的所有端口信息

3)jar包自带了json文件的使用手册,访问http://localhost:8080/__admin/docs/可看到如下界面:

点击Swagger_UI可以看到具体每种请求JSON的写法:


我们也可以在官网上查看JSON文件的写法:http://wiremock.org/docs/api/


4、录制/回放

1)打开:http://localhost:8080/__admin/recorder/可看到如下界面:

2)输入目标URL,点击Record按钮进入录制状态。

3)以上面的userInfo接口为例,我们通过浏览器访问http://localhost:8080/userInfo?name=liming&age=23,wiremock收到请求后,然后向目标服务器发起请求http://localhost:9001/userInfo?name=liming&age=23,然后把目标服务器返回的结果返回给我们,同时记下请求和响应的内容。

4)点击stop按钮停止录制,此时可以看到在mappings文件夹中生成一个json文件,记录了之前的请求和响应内容。

5)后续再访问http://localhost:8080/userInfo?name=liming&age=23时,wiremock便会从之前录制的json文件中获取响应信息返回给我们,我们也可以修改json文件从而改变请求响应的内容。


通过引入依赖的方式使用

wiremock源码:https://github.com/spring-cloud/spring-cloud-contract/tree/master

官方例子:https://github.com/spring-cloud/spring-cloud-contract/tree/master/samples/wiremock-tomcat


具体代码请看(码云):https://gitee.com/wudiyong/WireMockEurekaServer.git


1、引入wiremock依赖

		<dependency> 
			<groupId>com.github.tomakehurst</groupId> 
			<artifactId>wiremock</artifactId>
			<version>2.12.0</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-contract-wiremock</artifactId>
		</dependency>


2、创建实例并启动

1)如果只是模拟一个普通的HTTP服务端,可以直接在main函数中创建WireMockServer实例并启动:

		FileSource filesRoot = new SingleRootFileSource(wireMockFilesRoot+"/"+appName);
		WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.options()
				.bindAddress(wireMockAddress).port(Integer.parseInt(wireMockPort)).fileSource(filesRoot));
		wireMockServer.start();
2)如果在Spring Boot环境中使用,可以通过以下方式:

	@Bean
	public WireMockServer wireMockServer(){
		//创建wiremock对象
		FileSource filesRoot = new SingleRootFileSource(wireMockFilesRoot+"/"+appName);
		WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.options()
				.bindAddress(wireMockAddress).port(Integer.parseInt(wireMockPort)).fileSource(filesRoot));
		wireMockServer.start();
		return wireMockServer;
	}

wireMockFilesRoot+"/"+appName:mappings文件夹所在的位置

3)如果与JUnit结合使用,可以通过如下方式:

@Rule
public WireMockRule wireMockRule = new WireMockRule(options().port(8080));

前两种方式和执行jar文件启动方式一样,都可以通过http://localhost:8080/__admin/recorder/来开启/关闭录制

3、特别地,我们需要模拟一个Eureka服务端,我们的服务需要向注册中心注册,所以,选择上面第二种方式使用wiremock

程序中包含两个web服务:

一个是Spring Boot web,用于向注册中心注册,接收请求,然后将请求发到wiremock服务器

另一个是wiremock,用于模拟返回结果

代码如下:

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.tomakehurst.wiremock.WireMockServer;
@RestController
public class MockController {
	@Autowired
	RestTemplate restTemplate;
	
	@Autowired
	WireMockServer wireMockServer;
	
	@Value("${wireMock.address}")
	private String wireMockAddress;
	
	@Value("${wireMock.port}")
	private String wireMockPort;
	
	private static boolean isProxy = false;
	
	@RequestMapping(value = "/**", method = RequestMethod.GET)
	public Object getAll(HttpServletRequest httpServletRequest ,@RequestParam Map<String, Object> requestMap) {
		StringBuffer mocoUrl = new StringBuffer();
		mocoUrl.append("http://").append(wireMockAddress).append(":")
				.append(wireMockPort).append(httpServletRequest.getServletPath());
		if(!requestMap.isEmpty()){
			mocoUrl.append("?");
			boolean first = true;
			for(String key:requestMap.keySet()){
				if(!first){
					mocoUrl.append("&");
				}
				first = false;
				mocoUrl.append(key).append("={").append(key).append("}");
			}
		}
		String jsonStr = restTemplate.getForEntity(mocoUrl.toString(), String.class,requestMap).getBody();
		Object object = JSONObject.parse(jsonStr);
		return object;
	}
	
	@RequestMapping(value = "/**", method = RequestMethod.POST)
	public Object postAll(HttpServletRequest httpServletRequest ,@RequestBody Object requestBody) {
		String requestJsonStr = JSON.toJSONString(requestBody);
		StringBuffer mocoUrl = new StringBuffer();
		mocoUrl.append("http://").append(wireMockAddress).append(":")
				.append(wireMockPort).append(httpServletRequest.getServletPath());
		RestTemplate restTemplate = new RestTemplate();
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
//		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		HttpEntity<String> formEntity = new HttpEntity<String>(requestJsonStr, headers);
		String jsonStr = restTemplate.postForEntity(mocoUrl.toString(), formEntity,String.class).getBody();
		Object object = JSONObject.parse(jsonStr);
		return object;
	}
	
	@RequestMapping(value = "/proxyOn" , method = RequestMethod.GET)
	public String proxyOn(@RequestParam String proxyPath){
		if(isProxy){
			wireMockServer.stopRecording();
		}
		isProxy = true;
		//开启录制
		wireMockServer.startRecording(proxyPath);
		return "Proxy is on! The proxyPath is:" + proxyPath;
	}
	
	@RequestMapping(value = "/proxyOff",method = RequestMethod.GET)
	public String proxyOff(){
		if(isProxy){
			//关闭录制
			wireMockServer.stopRecording();
		}
		isProxy = false;
		return "Proxy is off!";
	}
}


录制的步骤如下:

1)启动自己编写的模拟服务器和目标服务器

2)设置被录制的目标服务器地址,然后开启录制,有两种方式:通过wiremock提供的图形界面设置、调用上面代码提供的接口

3)触发客户端发送请求,如果模拟服务器和目标服务器同名,则该请求会按照一定策略分配到不同的服务器,默认是轮询方式,也就是说,触发两次,会有一次请求到达模拟服务器

4)关闭录制,此时看到mappings文件夹下生成了一个新的json文件,至此录制完成,当然可以一起录制多个请求,每次请求对应一个json文件

录制结束后,后续的测试便不需要启动目标服务器了,模拟服务器会根据请求的url和参数返回对应的结果,可以根据需要修改录制结果或手动编写json文件。






















  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值