一,mock测试
参考文档:
‘ 接口测试——接口协议抓包分析与mock_L3-CSDN博客 ’
1,mock的价值
- 不依赖第三方数据
- 节省工作量
- 节省联调
2,常用的mock工具
- Charles 测试工程师常用
- BurpSuite 黑客常用
- Fiddler 只能 Windows 上使用
- Nginx 服务器反向代理与修改
- Mitmproxy 代理工具 可编程
- Wiremock 代理工具 可编程
二,mock实战
(1)Charles工具
1.1 Rewrite方式(原理)
设置方法:
- Tools → Rewrite
- 勾选 Enable Rewrite
- 点击下方 Add 按钮新建一个重写的规则
- 在右侧编辑重写规则
- 点击 ok 生效
1.2 Map Local 方式
原理:
设置方法:
- 准备本地接口响应数据
- 配置 Map Local
- 选择要进行 Map Local 的接口
- 鼠标右键 – 选择 Map Local 选项进入设置界面
- Map From 填写接口的信息
- Map To 选择本地文件
- 修改 Map Local 配置:Tools – Map Local
1.3 Map Remote 方式
设置方法:
- 选择接口,点击鼠标右键,选择 Map Remote 进入到设置页面
- 设置重定向的接口信息
- 点击 ok 生效
- 修改设置:Tools – Map Remote 找对对应接口双击进入修改界面
(2) WireMock
2.1 依赖导入
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.32.0</version>
<scope>test</scope>
</dependency>
2.2 使用的 mock流程模板
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
//启动服务的端口号
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089)); //No-args constructor will start on port 8080, no HTTPS
wireMockServer.start();
configureFor(8089);
// 做一些业务请求逻辑
...
WireMock.reset();
// 完成之后
wireMockServer.stop();
2.2 实战 - mock发送一个请求,请求参数匹配规则
调用下记代码发送请求,然后通过浏览器输入“localhost:8089”,回车查看返回结果是否与body内容匹配
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
public class WireMockTest {
@Test
void baseMockTest() throws InterruptedException {
//启动服务的端口号
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
//No-args constructor will start on port 8080, no HTTPS(没有定义端口号的情况下,默认端口号是8080)
wireMockServer.start();
configureFor(8089);
//业务逻辑 - 写一个get请求,要求其返回body体的内容
stubFor(get(urlEqualTo("/wiremock"))
.willReturn(aResponse().withBody("this is a mock server")));
Thread.sleep(999999);
//重置数据
WireMock.reset();
// 完成之后
wireMockServer.stop();
}
@Test
void baseMock404Test() throws InterruptedException {
//启动服务的端口号
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
//No-args constructor will start on port 8080, no HTTPS(没有定义端口号的情况下,默认端口号是8080)
wireMockServer.start();
configureFor(8089);
//业务逻辑 - 写一个get请求,定义状态码不同,返回body体的内容不同
stubFor(get(urlEqualTo("/wiremock"))
.willReturn(aResponse().withStatus(404).withBody("this is a mock server 404")));
Thread.sleep(999999);
//重置数据
WireMock.reset();
// 完成之后
wireMockServer.stop();
}
}
2.4 实战 - mock发送一个带请求参数的请求,请求参数匹配规则
- 调用下记mock发起请求
@Test
void requestMock() throws InterruptedException {
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
wireMockServer.start();
configureFor(8089);
// any - 希望匹配任何请求方法,带参数的请求必须用urlPathEqualTo
stubFor(any(urlPathEqualTo("/wiremock"))
.withHeader("Accept",containing("xml"))
.withCookie("session",matching(".*12345*"))
.withQueryParam("search_term",equalTo("WireMock"))
.withBasicAuth("demi@ceshiren.com","hogwarts1234")
.withRequestBody(matchingJsonPath("$.a",equalTo("1")))
.willReturn(aResponse().withStatus(200).withBody("request mock server !!"))
);
//强制等待
sleep(999999);
WireMock.reset();
wireMockServer.stop();
}
- mock一个匹配上述规则的请求并调用,通过浏览器查看对应接口请求传参和返回响应是否匹配
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
public class RequestTest {
@Test
void requestTest(){
given().log().all()
.header("Accept","xml")
.cookie("session","12345")
.queryParam("search_term","WireMock")
.auth().preemptive().basic("demi@ceshiren.com","hogwarts1234")
.body("{a:1,b:99,c:2}")
.when()
.post("http://localhost:8089/wiremock")
.then().log().all();
}
}
2.5 实战 - 发送多个请求并返回响应,在浏览器输入http://localhost:8089/__admin/可以查看多个请求响应结果
@Test
void requestMock2() throws InterruptedException {
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
wireMockServer.start();
configureFor(8089);
stubFor(get(urlEqualTo("/wirmock/resp"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/plain")
.withBody("Hello WireMock ResponseMath!")));
//常见的响应缩写
stubFor(get("/fine-with-body")
.willReturn(ok("body content")));
stubFor(get("/json")
.willReturn(okJson("{ \"message\": \"Hello\" }")));
stubFor(get("/annother")
.willReturn(temporaryRedirect("/new/place")));
stubFor(get("/new/place")
.willReturn(okJson("{ \"message\": \"302 local\" }")));
stubFor(get("/sorry-no")
.willReturn(unauthorized()));
stubFor(get("/status-only")
.willReturn(status(418)));
sleep(999999);
WireMock.reset();
wireMockServer.stop();
}
- 多个请求的情况下,可以通过atPriority()方法来设置stub的匹配优先级,数字越小优先级越高
@Test
void requestMock3() throws InterruptedException {
WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
wireMockServer.start();
configureFor(8089);
// any - 希望匹配任何请求方法,带参数的请求必须用urlPathEqualTo
stubFor(get(urlMatching("/api/.*")).atPriority(4)
.willReturn(aResponse().withStatus(200).withBody("api demo")));
stubFor(get(urlMatching("/api/resource")).atPriority(1)
.willReturn(aResponse().withStatus(200).withBody("resource date")));
stubFor(any(anyUrl()).atPriority(5)
.willReturn(aResponse().withStatus(401).withBody("mo matching")));
sleep(999999);
WireMock.reset();
wireMockServer.stop();
}
2.6 实战 - WireMock录制功能
(a)下载wiremock的jar包(这里是通过docker下载),完成后浏览器打开
http://192.168.43.68:8080/__admin/recorder/ 录制网页
(b)填写需要录制的地址,点击record开始录制
- 测试用的url为:https://httpbin.ceshiren.com
(c)通过 http://192.168.43.68:8080 可以直接访问原本的测试地址,表明已实现代理
(d)通过修改Mappings文件的内容,然后重启WireMock之后,对应的修改内容会同步展示在页面
- 这种方法太繁琐,不推荐,更推荐通过代码的方式来修改返回的内容,具体见下记。
2.7 实战 - WireMock通过代码来修改返回的内容
- (a)代码示例:修改response的返回内容
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;
import org.junit.jupiter.api.Test;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static java.lang.Thread.sleep;
public class ProxyMockTest {
@Test
void proxyMock() throws InterruptedException {
int port = 8089;
//代理规则,指定返回的结果
WireMockServer wireMockServer = new WireMockServer(
wireMockConfig().port(port)
.extensions(new ResponseTransformer() {
//通过重写transform方法,可以对透传后返回的response进行修改
@Override
public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
String bodyAsString = response.getBodyAsString();
return Response.Builder.like(response)
.body(response.getBodyAsString().replace("Other Utilities", "Mock Other Utilities"))
.build();
}
@Override
public String getName() {
return "ResponseTransformerDemo";
}
})
);
wireMockServer.start();
configureFor(port);
//proxiedFrom()填写的是实际访问的地址,通过proxiedFrom()方法使stub匹配到的请求,可以透传到真正的后端
stubFor(get(urlMatching(".*"))
.willReturn(aResponse().proxiedFrom("https://httpbin.ceshiren.com")));
sleep(999999);
WireMock.reset();
wireMockServer.stop();
}
}
- (b)访问mock地址http://localhost:8089 并查看对应的内容已修改