简介
为什么要学习 Mock
- 提高测试深度
- 提高测试效率
- 降低成本
- 测试股票软件,模拟当天股票全部上涨
- 测试股票软件,模拟当天股票全部下跌
- 测试股票软件,模拟部分股票涨幅10%
Test Double 测试替身
- Dummy 占位对象 对象被传递但从未实际使用过。通常它们仅用于填充参数列表。
- Fake 假对象 对象实际上有工作实现,但通常采取一些捷径,这使得它们不适合生产(内存数据库就是一个很好的例子)。
- Stubs 桩对象 为测试期间调用提供预设答案,通常根本不响应任何超出测试程序的内容。
- Spies 间谍对象 它们还根据调用方式记录一些信息。其中一种形式可能是电子邮件服务,它记录发送了多少消息。
- Mocks 模拟对象 是我们在这里谈论的:预先编程的对象,这些期望形成了它们期望接收的调用的规范。
测试替身关键概念的区别
一个真实的技术架构例子
- dummy 只要端口开着就行
- fake 内存数据库
- spy UI 界面后端请求记录
- stub 假的登录后端服务
- hook 新用户判断方法修改
- proxy 代理转发机制
- mock 模拟对象
Fake 假对象 定义
Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an InMemoryTestDatabase is a good example).
假对象实际上有工作实现,但通常采取一些捷径,这使得它们不适合生产(纯内存数据库就是一个很好的例子)。
Fake 应用场景
Stub 桩定义
Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.
为测试期间调用提供预设答案,通常根本不响应任何超出测试程序的内容。
Stub 应用场景 Swagger
Setup Stub Server
java -jar moco-runner-1.2.0-standalone.jar http -p 12345 -c foo.json
{
"request" :
{
"uri" : "/foo",
"queries" :
{
"param" : "blah"
}
},
"response" :
{
"text" : "bar"
}
}
Mock 模拟对象定义
Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don’t expect and are checked during verification to ensure they got all the calls they were expecting.
模拟预编程了期望,这些期望形成了他们期望接收的调用的规范。如果他们收到了他们不期望的调用,他们可以抛出异常,并在验证过程中进行检查以确保他们得到了他们期望的所有调用。
Mock 两种应用场景
- mock on stub:按需返回期望数据
- mock on proxy:按需返回真实数据的修改副本
常⽤的 Mock 工具
- Charles 测试工程师常用
- BurpSuite 黑客常用
- Fiddler 只能 Windows 上使用
- Nginx 服务器反向代理与修改
- Mitmproxy 代理工具 可编程
- Wiremock 代理工具 可编程
mitmproxy
mitmproxy is a set of tools that provide an interactive, SSL/TLS-capable intercepting proxy for HTTP/1, HTTP/2, and WebSockets.
mitmproxy mock on proxy
python3 -m http.server
mitmdump -p 8001 -m reverse:127.0.0.1:8000 --flow-detail 4 -B '/~bs .*Directory.*/Directory/ceshiren.com mock'
mitmproxy 强大的插件机制 Addons
- dns
- tcp
- cert
- http/https
- websocket
adb mock 案例
"""
测试人社区 https://ceshiren.com
"""
import sys
from mitmproxy import ctx
from mitmproxy import tcp
from mitmproxy.utils import strutils
from mitmproxy.tools.main import mitmdump
def tcp_message(flow: tcp.TCPFlow):
message = flow.messages[-1]
old_content = message.content
message.content = old_content.replace(
b":0;localabstract:webview_devtools_remote_",
b": 0;localabstract:xweb_devtools_remote_"
)
ctx.log.info(
"[tcp_message{}] from {} to {}:\n{}".format(
" (modified)" if message.content != old_content else "",
"client" if message.from_client else "server",
"server" if message.from_client else "client",
strutils.bytes_to_escaped_str(message.content))
)
if __name__ == '__main__':
sys.argv = ["", "-p", "5038", "--rawtcp", "--mode", "reverse:http://localhost:5037/", "-s", sys.argv[0], "-vv"]
mitmdump()
WireMock
The flexible tool for building mock APIs.
Create stable development environments, isolate yourself from flakey 3rd parties and simulate APIs that don’t exist yet.
wiremock stub
java -jar wiremock-jre8-standalone-2.33.2.jar
{
"request": {
"method": "GET",
"url": "/wiremock"
},
"response": {
"status": 200,
"body": "Easy!"
}
}
mock on stub
@Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
mock on proxy
wm.stubFor(get(urlPathEqualTo("/templated"))
.willReturn(aResponse()
.proxiedFrom("$!request.headers.X-WM-Proxy-Url")
.withTransformers("response-template")));
public class ExampleTransformer extends ResponseDefinitionTransformer {
@Override
public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files, Parameters parameters) {
String content=responseDefinition.getTextBody().replace("霍格沃兹", "mock");
System.out.println(responseDefinition.getTextBody());
System.out.println(content);
return new ResponseDefinitionBuilder()
.withHeader("MyHeader", "Transformed")
.withStatus(200)
.withBody(content)
.build();
}
@Override
public String getName() {
return "hogwarts_mock";
}
}
总结
- 了解测试替身的实现方式,统一沟通概念
- 了解 Mock 的常见应用场景
推荐学习
【霍格沃兹测试开发】7天软件测试快速入门带你从零基础/转行/小白/就业/测试用例设计实战
【霍格沃兹测试开发】最新版!Web 自动化测试从入门到精通/ 电子商务产品实战/Selenium (上集)
【霍格沃兹测试开发】最新版!Web 自动化测试从入门到精通/ 电子商务产品实战/Selenium (下集)
【霍格沃兹测试开发】明星讲师精心打造最新Python 教程软件测试开发从业者必学(上集)
【霍格沃兹测试开发】明星讲师精心打造最新Python 教程软件测试开发从业者必学(下集)
【霍格沃兹测试开发】精品课合集/ 自动化测试/ 性能测试/ 精准测试/ 测试左移/ 测试右移/ 人工智能测试
【霍格沃兹测试开发】腾讯/ 百度/ 阿里/ 字节测试专家技术沙龙分享合集/ 精准化测试/ 流量回放/Diff
【霍格沃兹测试开发】Pytest 用例结构/ 编写规范 / 免费分享
【霍格沃兹测试开发】JMeter 实时性能监控平台/ 数据分析展示系统Grafana/Docker 安装
【霍格沃兹测试开发】接口自动化测试的场景有哪些?为什么要做接口自动化测试?如何一键生成测试报告?
【霍格沃兹测试开发】面试技巧指导/ 测试开发能力评级/1V1 模拟面试实战/ 冲刺年薪百万!
【霍格沃兹测试开发】腾讯软件测试能力评级标准/ 要评级表格的联系我
【霍格沃兹测试开发】Pytest 与Allure2 一键生成测试报告/ 测试用例断言/ 数据驱动/ 参数化
【霍格沃兹测试开发】App 功能测试实战快速入门/adb 常用命令/adb 压力测试
【霍格沃兹测试开发】阿里/ 百度/ 腾讯/ 滴滴/ 字节/ 一线大厂面试真题讲解,卷完拿高薪Offer !
【霍格沃兹测试开发】App自动化测试零基础快速入门/Appium/自动化用例录制/参数配置
【霍格沃兹测试开发】如何用Postman 做接口测试,从入门到实战/ 接口抓包(最新最全教程)
【霍格沃兹测试开发】6 小时轻松上手功能测试/ 软件测试工作流程/ 测试用例设计/Bug 管理