写点什么

接口测试:Mock 技术体系

作者:测试人
  • 2024-06-26
    北京
  • 本文字数:2648 字

    阅读完需:约 9 分钟

简介

为什么要学习 Mock

  • 提高测试深度

  • 提高测试效率

  • 降低成本

  1. 测试股票软件,模拟当天股票全部上涨

  2. 测试股票软件,模拟当天股票全部下跌

  3. 测试股票软件,模拟部分股票涨幅 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.servermitmdump -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 ctxfrom mitmproxy import tcpfrom mitmproxy.utils import strutilsfrom 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

@Testpublic 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 的常见应用场景

软件测试开发免费视频教程分享


发布于: 刚刚阅读数: 5
用户头像

测试人

关注

专注于软件测试开发 2022-08-29 加入

霍格沃兹测试开发学社,测试人社区:https://ceshiren.com/t/topic/22284

评论

发布
暂无评论
接口测试:Mock 技术体系_软件测试_测试人_InfoQ写作社区