博客 / 詳情

返回

一文帶你瞭解Mock 技術體系

簡介

為什麼要學習 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.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 案例



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 的常見應用場景
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.