今天想给大家介绍下我在工作中用到的两个工具,并用这两个工具来快速搭建一个可视化的 Http Mock 平台。一个工具是 WireMock:这个工具相信大家应该不会陌生,这里也就不在过多的进行赘述,没有接触过得请自行百度,相信对你得测试工作会有所帮助。第二个工具是 renren-fast:renren-fast 是一个轻量级的 Spring Boot 快速开发平台,能快速开发项目并交付项目。俨然是代码偏弱得小伙伴得福音,可以大大降低代码编写量,提升开发效率。对于测试来说可以更为简便得开发一个属于自己得平台。这个工具定位是为了方便开发各种后台管理系统,当然你想要使用,还是需要一定的代码能力的,所以该补的基础还是要补的!~
平台搭建思路如下和部分关键代码如下 (demo 地址:https://gitee.com/meng_zi_meng_dad/mock_demo_vue):
1、开发环境搭建,下载 renren-fast 前后端代码、代码创建器,创建数据库,并完成调试启动。请参考以下文档:
--https://www.oschina.net/p/renren-security-boot?hmsr=aladdin1e1
--https://www.renren.io/guide/#end
2、在 pom 中增加 wiremock 相关的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-wiremock</artifactId>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>2.19.0</version>
</dependency>
3、编写代码,项目启动后启动 WireMock Client(命名为 MockRunner.java 存放位置为 io.renren.common.utils 下)
package io.renren.common.utils;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.common.SingleRootFileSource;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import io.renren.modules.sys.service.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.io.File;
@Component
public class MockRunner implements ApplicationRunner {
@Autowired
private SysConfigService sysConfigService;
@Override
public void run(ApplicationArguments args) throws Exception {
//wiremock文件存放根目录
FileSource filesRoot = new SingleRootFileSource("D:\\wiremock");
File path = new File(sysConfigService.getValue("wireMockFilesRoot")+File.separator+"mappings");
if (!path.exists() || !path.isDirectory()){
path.mkdirs();
}
WireMockServer wireMockServer;wireMockServer = new WireMockServer(WireMockConfiguration.options()
.bindAddress("127.0.0.1").port(9090).fileSource(filesRoot));
wireMockServer.start();
System.out.println("----------------------------------------WireMock启动成功-------------------------------------------");
}
}
4、设计 mock 存储的表结构,用代码生成器生成代码 (renren-fast 自带),并加入到前后端代码中,并完善页面显示
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `mcok_case_mapping`
-- ----------------------------
DROP TABLE IF EXISTS `mcok_case_mapping`;
CREATE TABLE `mcok_case_mapping` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`test_case_id` bigint(20) NOT NULL,
`uuid` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for `mock_case`
-- ----------------------------
DROP TABLE IF EXISTS `mock_case`;
CREATE TABLE `mock_case` (
`uuid` varchar(255) DEFAULT NULL,
`response` longtext,
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`case_name` varchar(255) DEFAULT NULL,
`case_url` longtext,
`has_header` bit(1) NOT NULL,
`header` text,
`status` bigint(20) NOT NULL,
`request_data` longtext,
`request_data_type` varchar(255) DEFAULT NULL,
`request_method` varchar(255) DEFAULT NULL,
`visible` int(11) NOT NULL,
`from_case` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19879 DEFAULT CHARSET=utf8;
5、增加 WireMock 相关的接口,生成 mock 接口
package io.renren.modules.mock.controller;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.http.HttpHeader;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import com.google.gson.Gson;
import io.renren.common.utils.Constant;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.R;
import io.renren.modules.mock.entity.MockCaseEntity;
import io.renren.modules.mock.service.MockCaseService;
import io.renren.modules.sys.service.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
/**
*
* @date 2019-11-26 16:11:19
*/
@RestController
@RequestMapping("mock/mockcase")
public class MockCaseController extends Constant {
@Autowired
private MockCaseService mockCaseService;
@Autowired
private SysConfigService sysConfigService;
/**
* 列表
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = mockCaseService.queryPage(params);
return R.ok().put("page", page);
}
/**
* 信息
*/
@RequestMapping("/info/{id}")
public R info(@PathVariable("id") Long id){
MockCaseEntity mockCase = mockCaseService.getById(id);
return R.ok().put("mockCase", mockCase);
}
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody MockCaseEntity mockCase){
mockCase.setVisible(VISIBLE);
//调用wiremock相关接口
if(mockCase.getUuid()!=null && mockCase.getUuid().contains("-")){
File file = new File(sysConfigService.getValue("wireMockFilesRoot")+File.separator+"mappings");
File[] mappings =file.listFiles();
List<File> mapping = Arrays.stream(mappings).filter(p->p.getAbsolutePath().contains(mockCase.getUuid())).collect(Collectors.toList());
if(mapping.size()>0){
mapping.get(0).delete();
}
}
configureFor(sysConfigService.getValue("wireMockAddress"), Integer.parseInt(sysConfigService.getValue("wireMockPort")));
HttpHeaders headers = new HttpHeaders();
if(mockCase.getHasHeader()!=null && mockCase.getHasHeader() && mockCase.getHeader().split("\\|\\|").length>0){
for (String temp:mockCase.getHeader().split("\\|\\|")
) {
HttpHeader header = new HttpHeader(temp.split("\\|")[0],temp.split("\\|")[1]);
headers.plus(header);
}
}else{
mockCase.setHasHeader(false);
mockCase.setHeader("");
}
StubMapping stubMapping = null;
if (mockCase.getRequestMethod().equalsIgnoreCase(GET)){
stubMapping = stubFor(get(urlEqualTo(mockCase.getCaseUrl()))
.willReturn(aResponse()
.withHeaders(headers)
.withStatus(mockCase.getStatus())
.withBody(mockCase.getResponse())));
}else{
if(mockCase.getRequestDataType().equalsIgnoreCase(JSON)){
stubMapping = stubFor(post(urlEqualTo(mockCase.getCaseUrl())).withRequestBody(equalToJson(mockCase.getRequestData()))
.willReturn(aResponse()
.withStatus(mockCase.getStatus())
.withBody(mockCase.getResponse())));
}
if(mockCase.getRequestDataType().equalsIgnoreCase(FORM_DATA)){
Map<String, String> map = new Gson().fromJson(mockCase.getRequestData(), Map.class);
String temp = ".*";
for (String key : map.keySet()) {
temp += key + ".*" + map.get(key).replaceAll("\\{", "\\\\{").replaceAll("\\}", "\\\\}")
+ ".*";
}
stubMapping = stubFor(post(urlEqualTo(mockCase.getCaseUrl())).withRequestBody(matching(temp))
.willReturn(aResponse()
.withStatus(mockCase.getStatus())
.withBody(mockCase.getResponse())));
}
}
mockCase.setUuid(stubMapping.getUuid().toString());
mockCaseService.saveOrUpdate(mockCase);
WireMock.saveAllMappings();
return R.ok();
}
/**
* 删除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Long[] ids){
for (Long id:ids
) {
File file = new File(sysConfigService.getValue("wireMockFilesRoot")+File.separator+"mappings");
File[] mappings =file.listFiles();
List<File> mapping = Arrays.stream(mappings).filter(p->p.getAbsolutePath().contains(mockCaseService.getById(id).getUuid())).collect(Collectors.toList());
if(mapping.size()>0){
mapping.get(0).delete();
}
}
mockCaseService.removeByIds(Arrays.asList(ids));
return R.ok();
}
}
效果如下: