MockServer expectation callback 動態 進階 docker java API linux webservice

進階使用 MockServer (Expectation,Callback,API)

林志衡 Eric Lin 2021/09/10 18:04:00
67

前言

開發產品或專案如果有需要介接/串接外部 API,如政府機關的 API 或是 Webservice,有可能會因為安全性的限制,開發時只有看到API規格而無法在開發中實際呼叫那些 API 做測試。如此一來,開發過程就只能猜測或祈禱上天保佑不會出錯。而測試延後至佈署 (deploy) 到正式環境才開始,面臨一旦出錯,勢必延宕交付進度的窘境。因此,使用工具模擬外部 API 就顯得格外重要。目前較常見的工具是 Postman,SoapUI,以及 MockServer。這篇文章將說明 MockServer 的使用方法。

另一位作者的文章 "MockServer 入門: 輕鬆整合前後端接口" 介紹了幾種安裝方式及如何用 Java 寫 Expectation,要寫成 junit 的讀者可以參考。這篇文章主要是說明如何啟動獨立的 MockServer,並詳細說明各種 Expectation 的建立方式。

 

目錄

* Expectation

    - 基本結構: httpRequest, httpResponse

    - 進階使用: times.priority

    - Callback

* 啟動 MockServer

    - 以 JAR 方式啟動

    - 以 Docker 方式啟動

* MockServer API

    - MockServer UI

    - 取得目前的 Expectation

    - 更新 Expectation

    - 停止 MockServer

* 心得分享: 模擬 Webservice

* Reference

 

Expectation

MockServer 的機制,便是讀取事先建立的 Expectation 列表,而每一個 Expectation 定義了 request 的條件以及對應的 response。上述另一篇文章說明了用 Java 定義 Expectation。這裡就介紹另一個格式: json。

 

基本結構: httpRequest, httpResponse

以下就是 Expectation 列表的基本結構。由一個 array (亦稱為 list,也就是列表) 包含一個以上的 json object (亦稱為 dictionary)。每個 json object 就代表一個 Expectation,是由一對 httpRequest 及 httpResponse 組成。

[
  {
    "httpRequest": {
      "method": "post",
      "path": "/myapi/dosomething1"
    },
    "httpResponse": {
      "headers": {
        "Content-Type": ["application/json; charset=utf-8"]
      },
      "body": {
        "uid": 1001,
        "name": "孫小毛",
      }
    }
  }
]

httpRequest 包含各種 request matcher,也就是說,當有人對 MockServer 送一個request,MockServer 就用這個收到的 request 裡的某些資訊當作 request 的條件來搜尋 Expectation,例如 HTTP method (GET, POST, PUT, ...) 或是 API path。request 的條件是用 AND 組合,所以列出來的條件要每個都符合,MockServer 才會選取這個 Expectation。

以上述 json 的第一個 Expectation為例子,要讓 MockServer 找到這個 Expectation 的條件就是 HTTP method 必須是 POST,而 API path 必須是 /myapi/dosomething1。如果其中一個條件不符合,MockServer 就會繼續搜尋 array 裡的下一個 Expectation,直到找到完全符合的為止。如果都沒找到,MockServer就會返回 HTTP error 404。換句話說,一個 Expectation 的條件越多就嚴謹,越少就越容易符合,端看開發時的需求。(還有其他條件可用,請參照 MockServer 網頁的 request matcher 部分)

注意: 由於是從 array 按照順序找,先找到的就用。所以如果某個 Expectation 的條件很廣,例如條件只有定義 method: "get"而沒有任何其他條件,而且還是列表的第一個,那麼所有 GET 的 request 都會符合這個 Expectation,MockServer 就會用這個 Expectation 所定義的 response 返回。

httpResponse 包含 headers 跟 body。headers 是一個 json object,而 body 可為 json object 或只是一個字串(如 XML 或 JWE 字串等)。除了 headers 跟 body,MockServer 也提供了各種 response 會包含的資訊可定義,如 status code 跟 cookies 等。請參照 MockServer 網頁的 response action 部分

注意: headers 的每一個 header 的值都必須是 array。如同上面的範例所表示,即使只有一個字串也需要包在array裡面。

基本的 Expectation 只需要 httpRequest + httpResponse。如果沒有需要更進階的用法,可直接跳到 "啟動 MockServer"。

 

回目錄

 

進階使用: times, priority, id

很多 API 規格會描述同一個 API 根據不同的情境而會返回不同的 response。最簡單的例子就是返回錯誤訊息。假如要同時測試一個 API 會返回成功的 response 跟錯誤訊息,MockServer 提供了幾種做法,其中一種便是使用 times 跟 priority。以下 json 是將上面 "基本結構: httpRequest, httpResponse" 裡的範例加以修改。

[
  {
    "httpRequest": {
      "method": "post",
      "path": "/myapi/dosomething1"
    },
    "httpResponse": {
      "headers": {
        "Content-Type": ["application/json; charset=utf-8"]
      },
      "body": {
        "uid": 1001,
        "name": "孫小毛",
      }
    }
  },
  {
    "id": "do_once",
    "httpRequest": {
      "method": "post",
      "path": "/myapi/dosomething1"
    },
    "httpResponse": {
      "statusCode": 422,
      "reasonPhrase": "無法處理 payload"
    },
    "times" : {
      "remainingTimes" : 1
    },
    "priority": 10
  }
]

上述範例加了一個新的 Expectation,id 是 "do_once",用來返回 HTTP error 422。可以看到兩個 Expectation 的 httpRequest 是完全一樣。根據基本結構的說明,MockServer 是由 array 的第一個開始找,所以 request 進來時,第一個 Expectation 應該會被選取。那麼,要如何更改順序,讓第二個 Expectation 優先被使用?

priority 就是用來定義優先序的。如果 Expectation 沒有特別定義 priority,那預設值為 0,而有定義的話,則以數字大者為優先。數字一樣者才會以順序做為選取的判斷。

那麼,另一個問題是,如果一個 Expectation 的優先序高,要如何讓兩個 Expectation 都能被使用到?

times 是一個 json object,包含 remainingTimes,其設定的數字即是限制該 Expectation 被選取的次數。一旦次數用完便不會再被選到,直到下次 MockServer 重啟 (或是更新 Expectation)。

如上面 json 所示,將 priority 跟 times 組合起來用,而 remainingTimes 只設定成 1。意思就是,當 request 第一次進來的時候,第二個 Expectation 因為 priority 數字較大,會優先被選取,但只會被用一次,之後再呼叫同一個 API 的話,就會用第一個 Expectation 來返回 response。

id 本身沒有功能性,其用途是當有需要更新 Expectation 時,可以用此 id 標註要更新的 Expectation。假設目前有 20 個 Expectations,使用者只想要更動其中一個 Expectation,可以只更動有某個 id 的 Expectation,而不用將所有 20 個 Expectations 都傳入。

 

回目錄

 

Callback

目前為止所介紹的方式都是將 response 定義在靜態的 json 裡,不論怎麼呼叫都會返回一樣的 response。那麼,如果有需要模擬每次呼叫的 response 都必須經過某種運算才能產生的話要怎麼做? 例如,假設某個 API 的規格說傳入的參數會經過加密後放入 response 裡返回,這樣要如何模擬這個 API 呢?

像這類會動態產生結果的 API,就可以實作 MockServer 的 callback 來模擬。基本的概念就是用 Java 寫一個 callback class 來處理 request 然後將結果返回。Callback class 需要打包成 JAR 然後在啟動 MockServer 時將這個 JAR 加到 classpath 裡即可。

首先從以下的 Expectation 列表來看:

[
  {
    "httpRequest":{
      "path":"/myapi/login"
    },
    "httpResponseClassCallback" : {
      "callbackClass" : "com.tpisoftware.myapi.callback.LoginPage"
    }
  },
  {
    "httpRequest":{
      "path":"/myapi/data"
    },
    "httpResponseClassCallback" : {
      "callbackClass" : "com.tpisoftware.myapi.callback.DataCallback"
    }
  }
]

上面的 Expectation 列表裡定義了兩個 Expectation,分別處理 "/myapi/login" 及 "/myapi/data" 這兩個 request,但 response 的部分從 httpResponse 換成了 httpResponseClassCallback。

httpResponseClassCallback 是一個 json object,包含了 callbackClass,用來定義 request 要由哪個 Java class 來處理並產生 response。注意 Java class 須連 package 名。

以下為 LoginPage 這個 class。這個 class 用來示範如何將一個檔案的內容讀取成字串再將其當作 response body 返回。

 

package com.tpisoftware.myapi.callback;

import org.mockserver.file.FileReader;
import org.mockserver.mock.action.ExpectationResponseCallback;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;


public class LoginPage implements ExpectationResponseCallback {

	private final String FILE_PATH = "pages/login.html";

	@Override
	public HttpResponse handle(HttpRequest httpRequest) throws Exception {
		String html = FileReader.readFileFromClassPathOrPath(FILE_PATH);

		return HttpResponse.response()
				.withHeader("Content-type", "text/html; charset=utf-8")
				.withBody(html);
	}
}

一個 Callback class 的基本結構就是實作 ExpectationResponseCallback 這個 interface 然後 override 掉 handle() 這個 method。

以上範例並沒有什麼運算,只是將靜態的 HTML 檔讀出後返回,這樣的做法就跟把整個 HTML 寫成字串 (例如 <html><body>...</body></html>) 放到 Expectation json 裡面是一樣的。這樣做的好處是 json 可以保持整齊,比較好讀;缺點就是每次要改動就得重新編譯。讀者可以根據狀況自行決定用哪種作法。

以下為 DataCallback 這個 class,用來示範如何取得 request 裡的 query string 以及如何做轉導 (redirect):

package com.tpisoftware.myapi.callback;

import java.util.Base64;

import org.mockserver.mock.action.ExpectationResponseCallback;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
import org.mockserver.model.Parameters;

public class MyEGovDataCallback implements ExpectationResponseCallback {

    @Override
    public HttpResponse handle(HttpRequest httpRequest) throws Exception {

        // 如果確定在 URL 的 query string 只會有一個 uid,也可以寫成:
        // String uid = httpRequest.getFirstQueryStringParameter("uid");
        Parameters queryString = httpRequest.getQueryStringParameters();
        String uid = queryString.getValues("uid").get(0);

        // 將 uid 轉成 Base64 (url-safe) 的字串
        String b64str = Base64.getUrlEncoder().encodeToString(uid.getBytes());
        String url = String.format("https://www.tpisoftware.com?b=%s", b64str);

        return HttpResponse.response()
                .withStatusCode(302)
                .withHeader("Location", url);
    }
}

上述範例就是將 URL 的 query string 中讀出 "uid" 的值,將其轉換成 Base64 字串,再轉導到昕力資訊的首頁並帶上那個 Base64 字串。 每次呼叫的 uid 不同,所以 Base64 字串也會跟著改變。像這樣需要運算才能產生的 response 就能透過 callback 實現。其他應用方式,例如收到 request 之後需要先呼叫某個 API 進行串接,或是需要連接 DB 取資料等,都可以透過 callback 來模擬,就留給讀者自行實驗。

 

回目錄

 

啟動 MockServer

將 Expectation 列表 (以及包含 callback class 的 JAR) 準備好後,就可以啟動 MockServer。啟動的方式有多種,這裡介紹兩種方式: 下載 MockServer 的可執行 JAR來啟動,或是安裝 Docker 以 container 方式啟動。

 

以 JAR 方式啟動

首先到 MockServer 的下載頁下載 JAR 檔,接著以 java 指令啟動 MockServer。Windows 上可開啟 Command Prompt (cmd.exe),Linux 或 Mac 則開啟 Terminal。以下說明是以 Windows 的 Command Prompt 執行。

注意: 如果是在 Windows 10 上,而且想要用 WSL2 裡的 Linux (例如 Ubuntu 20) 來啟動 MockServer 的話,會出現 MockServer 無法從 WSL2 以外的應用程式 (例如瀏覽器) 連上的問題。解決方法請參考昕力大學上的另一篇文章: "解決 WSL 2 裡的 Java 服務無法從外部連接的問題"。

 

JAR啟動方式1: 讀取 Expectations 的 json 檔,但不包含 callback class

1. 下載 MockServer 的 JAR 檔到某個文件夾裡。此範例是放在 C:\mockserver 裡。

2. 將 Expectation 列表存成 json 檔,也放到 C:\mockserver 裡。(放哪皆可,不必非跟 MockServer 的 JAR 檔放一起)

3. 開啟 Command Prompt 執行以下指令便可啟動。

java -Dmockserver.initializationJsonPath=C:\mockserver\expectations.json -Dfile.encoding=UTF-8 -jar C:\mockserver\mockserver-netty-5.11.2-jar-with-dependencies.jar -serverPort 1080 -logLevel DEBUG

參數說明:

* -Dmockserver.initializationJsonPath={Expectation 的 json 檔路徑}: 各位都清楚,"-D" 開頭的參數都是要傳入 Java 程式裡,由 System.getProperty() 取得的參數。此參數便是將 json 檔的路徑傳入,讓 MockServer 的執行程式讀取。

* -Dfile.encoding={encoding}: 同樣的,這個參數是告訴 MockServer 的執行程式說,expectations.json 檔要用某種 encoding 方式來解讀。如果 expectations.json 有中文,建議存成 UTF-8,並提供此參數。

* -serverPort {port}: 啟動 MockServer 的 port

* -logLevel {level}: MockServer 是用 slf4j 將訊息 log 下來,而這個參數便是用來設定 slf4j 的 log 等級

 

JAR啟動方式2: 讀取 callback class 的 JAR 檔

1. 下載 MockServer 的可執行 JAR 檔到某個文件夾裡。此範例是放在 C:\mockserver 裡。

2. 將 Expectation 列表存成 json 檔,也放到 C:\mockserver 裡。(放哪皆可,不必非跟 MockServer 的 JAR 檔放一起)

3. 將所有的 callback class 打包成一個 JAR 檔。同樣放到 C:\mockserver 裡。(放哪皆可,跟 MockServer 的 JAR 放一起較方便)

4. 開啟 Command Prompt 執行以下指令便可啟動。

java -Dmockserver.initializationJsonPath=C:\mockserver\request.json -Dfile.encoding=UTF-8 -cp "C:\mockserver\*" org.mockserver.cli.Main -serverPort 1080 -logLevel DEBUG

如果要將 callback class 的 JAR 加到 classpath,java 指令提供 "-cp {JAR 檔的路徑}" 將 JAR 加到 classpath (也可設定 CLASSPATH 環境變數固定加到 classpath 裡,依執行的情況決定)。但值得注意的是,這個指令並沒有 "-jar {MockServer JAR 檔}"。這是因為用 -jar 執行的話,-cp 會被忽略掉。因此,如果啟動 MockServer 需要加其他的 JAR,就需要用 -cp 把包括 MockServer 的 JAR 在內的所有 JAR 檔都加到 classpath,然後執行 MockServer 的主程式 "org.mockserver.cli.Main" 來啟動。(這也是為什麼上述步驟提到將 JAR 放在一起比較方便,因為這樣就可以如範例一樣,用 "*" 加文件夾裡全部的 JAR)

同樣的,如果想將參數傳給 callback class,也可以用 "-D" 的方式傳入,而在 callback class 裡用 System.getProperty() 讀取。

 

回目錄

 

以 Docker 方式啟動

注意: 截至 2021/08/19 為止,MockServer 尚未有 Windows 版本的 Docker image (見此連結),所以只能在 Linux 上的 Docker 啟動。WSL 2 的 Linux 也可以。以下說明便是以 WSL 2 的 Ubuntu 20 試驗過並可行,但亦需要解決 Java 服務在 WSL2 裡的 port-forwarding 的問題。詳細解決方法請搜尋昕力大學上的另一篇文章: "解決 WSL 2 裡的 Java 服務無法從外部連接的問題"。

又,此說明會用到幾個 Linux 及 Docker 的名詞,如 mount 或 container 等,建議先熟悉一下基本的 Linux 指令及 Docker 說明。此外,以下所有範例裡面,如果開頭有 "prompt$" 就表示是指令的提示,就像是 cmd.exe 會看到的 "C:\>" 一樣,並不是指令的一部分。沒有 "prompt$" 開頭的則是執行後的結果。

(假設已安裝 Docker Engine) 執行以下指令下載 MockServer 的 Docker image。指令是否需要用 sudo 執行則端看如何安裝 Docker Engine。

prompt$ docker pull mockserver/mockserver

下載後可執行以下指令確認:

prompt$ docker images
REPOSITORY              TAG       IMAGE ID       CREATED         SIZE
mockserver/mockserver   latest    12e4cc75d519   8 months ago    216MB
prompt$

接下來準備設定檔。跟以JAR方式啟動不同,無法從指令將參數傳入,所以要將所需的參數寫在設定檔案裡。設定檔名固定為 "mockserver.properties"。以下是設定檔的範例:

# Expectation json 檔的路徑
mockserver.initializationJsonPath=/config/expectations.json
# Expectation json 檔的 encoding
file.encoding=UTF-8
# 假設這個設定值是 callback class 需要的
enc_algorithm=AES

上述範例定義了幾個設定值。這些設定值都可以由 Java 的 System.getProperty() 取得。

* mockserver.initializationJsonPath=/config/{Expectation json 檔的路徑}: 定義 Expectation 列表的 json 路徑。

* file.encoding={encoding}: 定義 Expectation json 檔的 encoding

而像是 enc_algorithm 為自定義的設定,假設 callback class 需要某些參數便可如此寫在設定黨裡。

需特別注意的是,Expectation json 檔案路徑的開頭為 "/config"。這不是 Linux 上的 /config,而是 MockServer container 裡面的 /config。Docker container 裡面的程式只能存取 container 裡的文件夾,至於 container 裡的文件夾實際上是對應到 container 外面的哪個文件夾則由 Docker 的指令來 mount。

以 MockServer container 為例子,主程式能存取的 container 裡的其中一個文件夾就是 /config。設定檔及 Expectation json 檔皆需放到 Linux 上的某個文件夾裡,再將那個 Linux 的文件夾 mount 到 Docker container 裡的 /config,就可讓 MockServer 的主程式去讀取。以下範例就是將設定檔及 Expectation json 檔案都放到 Linux 上的 ~/mockserver/conf,再將其 mount 到 container 裡的 /config。

prompt$ docker run -d --rm -p 1080:1080 -v ~/mockserver/conf:/config mockserver/mockserver -serverPort 1080 -logLevel DEBUG
ee00baab4bb57f9845f776b8daae93b4bb5e7b185622e8def339f8ede5fafb8b
prompt$

上述範例就啟動了 MockServer 的 container。以下是各參數皆為 Docker 的參數,詳細可看 Docker 文件,在此僅簡單說明:

* -d: detach 的意思,也就是讓 container 以 daemon 的形式跑 (可想像為在背景跑)。

* --rm: 當 container 停止後就刪除。如果想保留,可去掉此參數,然後執行 "docker ps -a" 便可找到所有 container,包含已停止的。

* -p: port-forwarding, 將冒號左邊的 Linux 的 port 對應到冒號右邊的 container port。

* -v: 將冒號左邊的 Linux 上的文件夾 mount 到右邊的 container 文件夾。此為動態綁定 (bind mount),container 停止後便消失。

而 "mockserver/mockserver" 就是要啟動的 image。另外像是 "-serverPort 1080" 及 "-logLevel DEBUG" 皆為 MockServer 主程式用到的參數,必須放在 image 名稱後面。啟動後 (不論成功與否) 皆會提供一個 container ID,如範例中的 ee00baab4bb57...。

可以執行 "docker ps" 來看執行的狀態:

prompt$ docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS         PORTS                    NAMES
ee00baab4bb5   mockserver/mockserver   "java -Dfile.encodin…"   3 seconds ago   Up 3 seconds   0.0.0.0:1080->1080/tcp   heuristic_dhawan
prompt$

那麼,同樣的邏輯,如果有 callback 的 JAR 檔等任何需要加到 classpath 的 JAR 檔,也需要放到 Linux 上的某個文件夾再 mount。MockServer 會將 container 裡的 /libs 內所有的 JAR 都加到 classpath裡。

prompt$> docker run -d --rm -p 1080:1080 -v ~/mockserver/conf:/config -v ~/mockserver/libs:/libs mockserver/mockserver -serverPort 1080 -logLevel DEBUG
ac758a8028e9df15bf994738c1bf0b754b6fbfd758f3e5f75bd4dc38d9b70e0e
prompt$>

從上面範例可以看到一個指令裡可以有多個 -v 參數,將 "~/mockserver/conf" mount 到 /config,並將 "~/mockserver/libs" mount 到 /libs。

啟動後可以打開瀏覽器到 http(s)://{hostname-or-ip}:{port}/mockserver/dashboard 來看。如果有成功啟動,便會看到 MockServer UI

 

回目錄

 

MockServer API

MockServer 顧名思義,就是一個 Server,除了能讀取 Expectations 以建立 Rest API 之外,亦提供內建的 API 讓使用者可以遠端控制。以下介紹幾個較為常用的API。API 可用 curl 或是 Postman 等工具呼叫。以下範例是以 curl 示範。

 

MockServer UI

GET http(s)://{hostname-or-ip}:{port}/mockserver/dashboard

這不算是個 API 而是個網址。在瀏覽器輸入這個網址便能看到 MockServer 的畫面,如下:

MockServer UI 有四個欄位:

1. Log Messages: 列出 MockServer 的執行 log,最新的在最上面。

2. Active Expectations: 列出讀取到的 Expectation 列表。以此範例來看,裡面只有一個 Expectation。

3. Received Requests: 列出被呼叫的 HTTP request。從範例看到,目前有一次呼叫 GET /myapi/dosomething1。

4. Proxied Requests: MockServer 可設定成代理伺服器將 HTTP request 導向其他服務,此欄位會列出轉導的 request。

 

回目錄

 

取得目前的 Expectation

PUT http(s)://{hostname-or-ip}:{port}/mockserver/retrieve?type=ACTIVE_EXPECTATIONS

這個 API 可以取得已讀取的 Expectation 列表 (相當於 MockServer UI 裡的 Active Expectations 欄位)。用 curl 呼叫:

prompt$ curl -X PUT "http://localhost:1080/mockserver/retrieve?type=ACTIVE_EXPECTATIONS"
[ {
    "id" : "abcd1234",
    "priority" : 0,
    "httpRequest" : {
      "method" : "GET",
      "path" : "/myapi/dosomething1"
    },
    "httpResponse" : {
      "headers" : {
        "Content-Type" : [ "text/plain" ]
      },
      "body" : "Done!"
    },
    "times" : {
      "unlimited" : true
    },
    "timeToLive" : {
      "unlimited" : true
    }
} ]
prompt$

可以看到目前的 Expectation 列表以 API 的 response 形式返回。如果有需要從另一台主機經過網路更新 Expectation,可以此方式取得目前的列表,修改後再呼叫另一個 MockServer API (下面會介紹) 將 Expectation 增減或更新。

 

回目錄

 

更新 Expectation

PUT http://{hostname-or-ip}:{port}/mockserver/expectation

將目前的 Expectation 列表更新成呼叫此 API 傳入的 body。以上面的例子來看,目前只有一個 Expectation,其 id 為 "abcd1234"。想要更新此 Expectation 可以這樣做:

prompt$ curl -X PUT "http://localhost:1080/mockserver/expectation" -d '{                                                                                                                                              
  "id" : "abcd1234",                                                                                                                                                                                                                          
  "priority" : 0,                                                                                                                                                                                                                            
  "httpRequest" : {                                                                                                                                                                                                                       
    "method" : "GET",                                                                                                                                                                                                                      
    "path" : "/myapi/dosomething1"                                                                                                                                                                                                         
  },                                                                                                                                                                                                                                       
  "httpResponse" : {
    "headers" : {
      "Content-Type" : [ "text/plain" ]
    },
    "body" : "Well Done!"
  },
  "times" : {
    "unlimited" : true
  },
  "timeToLive" : {
    "unlimited" : true
  }
}'

#=== 為了方便閱讀將輸出跟上面的body分開,真正的 output 沒有分開 ===

[ {
  "id" : "abcd1234",
  "priority" : 0,
  "httpRequest" : {
    "method" : "GET",
    "path" : "/myapi/dosomething1"
  },
  "httpResponse" : {
    "headers" : {
      "Content-Type" : [ "text/plain" ]
    },
    "body" : "Well Done!"
  },
  "times" : {
    "unlimited" : true
  },
  "timeToLive" : {
    "unlimited" : true
  }
} ]
prompt$

上面的範例將 id 是 "abcd1234" 的 Expectation 更新了。更動很小,只是將 body 從 "Done!" 變成 "Well Done!"。更新成功便可看到更新後的整個 Expectation 列表以 API 的 response 返回。要檢查可以再次呼叫 API 取得目前的 Expectation 列表。這裡就省略了。

 

回目錄

 

停止 MockServer

PUT http://{hostname-or-ip}:{port}/stop

雖然停止 MockServer 可以直接把 cmd.exe 的視窗直接關掉,或是執行 Docker 指令將 container 停掉,不過為了確保 port 有確實的被釋放掉,還是用此 API 好好的停掉比較妥當。

以下就是簡單的範例:

prompt$> docker ps -a
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS         PORTS                    NAMES
8590e52a35b7   mockserver/mockserver   "java -Dfile.encodin…"   7 seconds ago   Up 7 seconds   0.0.0.0:1080->1080/tcp   brave_vaughan

prompt$> curl -X PUT "http://localhost:1080/stop"

prompt$> docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
prompt$>

可以看到,一開始的 docker ps -a 會列出 MockServer container 有正在執行,但用 curl 呼叫停止 MockServer 的 API 之後,container 就消失了 (因為是用 --rm 啟動的)。

 

回目錄

 

心得分享: 模擬 Webservice

現在知道可以用 MockServer 模擬 REST API,那如果有些服務還是 Webservice 呢?

Webservice 其實也是透過 HTTP/HTTPS 呼叫某個 URL,只是 request 跟 response body 都是 XML,要找出 XML 的格式要花一點小功夫。Webservice 一定會提供 WSDL 檔,只要解析 WSDL 檔就可以找出 request/response 的 XML。這時可用另一個工具 "SoapUI" 來解析。SoapUI 的使用方法不在此文章範圍,基本上就是用 SoapUI 讀取 WSDL 檔案便可看到 request/response 的 XML 格式,而且以模擬的角度來看,真正需要的只有 response 的 XML 格式,request 只要有 URL 即可。

有了 response XML 的格式之後,便可建立一個 MockServer 的 Expectation,其 httpRequest 的 path 就是 request URL,而 httpResponse 的 body 就是從 SoapUI 解析出來的 response XML。再來就需要讀一下 XML,推測哪個 XML element 代表哪些資訊 (例如 <uid></uid> 大概就是 user ID 等等),這部分就必須看 Webservice 提供的文件了。

 

回目錄

 

Reference

* MockServer Home

* Docker Reference Documentation

* WSL2 port forwarding is not working if accessed from java

    - 此問題亦包含在 WSL2 裡的 Java service 無法從外面連上。

    - 解決方法見昕力大學的另一篇文章: 解決 WSL 2 裡的 Java 服務無法從外部連接的問題

* Add Windows-based Docker image for MockServer

~全文完~

回目錄

林志衡 Eric Lin