一,mock测试
参考文档:
‘ 接口测试——接口协议抓包分析与mock_L3_303 接口协议-CSDN博客 ’
1,mock的价值
- 不依赖第三方数据
- 节省工作量
- 节省联调
2,常用的mock工具
- Charles 测试工程师常用
- BurpSuite 黑客常用
- Fiddler 只能 Windows 上使用
- Nginx 服务器反向代理与修改
- Mitmproxy 代理工具 可编程
- Wiremock 代理工具 可编程
3,mock实战 - Charles工具
3.1 Rewrite方式
原理:
设置方法:
- Tools → Rewrite
- 勾选 Enable Rewrite
- 点击下方 Add 按钮新建一个重写的规则
- 在右侧编辑重写规则
- 点击 ok 生效
3.2 Map Local 方式
原理:
设置方法:
- 准备本地接口响应数据
- 配置 Map Local
- 选择要进行 Map Local 的接口
- 鼠标右键 – 选择 Map Local 选项进入设置界面
- Map From 填写接口的信息
- Map To 选择本地文件
- 修改 Map Local 配置:Tools – Map Local
3.3 Map Remote 方式
原理:
设置方法:
- 选择接口,点击鼠标右键,选择 Map Remote 进入到设置页面
- 设置重定向的接口信息
- 点击 ok 生效
- 修改设置:Tools – Map Remote 找对对应接口双击进入修改界面
4,mock实战 - WireMock
4.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>
4.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();
4.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();
}
}
4.3 实战 - 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();
}
}
4.4 实战 - 发送多个请求并返回响应,在浏览器输入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();
}
4.5 实战 - 将WireMock的录制功能写成代码
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.extension.responsetemplating.ResponseTemplateTransformer;
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 ResponseTemplateTransformer(true),new ResponseTransformer() {
//通过重写transform方法,可以对透传后返回的response进行修改
@Override
public Response transform(Request request, Response response, FileSource fileSource, Parameters parameters) {
String body = response.getBodyAsString();
return Response.Builder.like(response)
.body(body.replace("Other Utilities","Other Utilities-this is proxy!"))
.build();
}
@Override
public String getName() {
return "ResponseTransformerDemo";
}
})
);
wireMockServer.start();
configureFor(port);
//通过proxiedFrom()方法使stub匹配到的请求,可以透传到真正的后端
stubFor(get(urlMatching(".*"))
.willReturn(aResponse().proxiedFrom("http://httpbin.ceshiren.com")));
sleep(999999);
WireMock.reset();
wireMockServer.stop();
}
}