WireMock+renren-fast 快速搭建 HTTP Mock 視覺化平臺思路

萌梓萌爸發表於2020-06-03

今天想給大家介紹下我在工作中用到的兩個工具,並用這兩個工具來快速搭建一個視覺化的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();
}

}

效果如下:



相關文章