Karate 是一款根據 Cucumber 的 API 測試框架,它結合了 BDD 的易讀性和 API 測試的靈活性。Karate DSL 簡潔易懂,即使不熟悉程式語言的測試人員也能快速上手。它支援 JSON、XML、字串等多種資料格式的驗證,並提供豐富的內建匹配器和斷言,方便開發者進行精確的 API 測試。此外,Karate 還支援資料驅動測試和在 IDE 中的斷點除錯,提升測試效率。
使用 Karate 編寫基礎測試
驗證回應型別
在進行 API 測試時,驗證回應的型別是非常重要的一步。Karate 提供了 responseType 關鍵字來檢查回應的型別。例如,若要驗證回應是否為 JSON 格式,可以使用以下程式碼:
Scenario: 檢查特定使用者的文章
Given url 'https://jsonplaceholder.typicode.com/posts'
When method get
Then status 200
And match responseType == 'json'
內容解密:
responseType可以被設定為json、string或xml,用於驗證回應的型別。- 使用雙等號
==進行值比較。 And關鍵字用於新增額外的檢查步驟,相當於另一個Then步驟。
比對值
最簡單的比對案例是檢查某個元素是否具有特定的值。例如,驗證第一個傳回的文章中 userId 是否為 1:
And match response[0].userId == 1
內容解密:
- 使用
==進行值的比較。 - 若比對失敗,Karate 將提供詳細的錯誤訊息,指出期望值與實際值的差異。
- 也可以使用
!=來檢查值是否不相等。
檢查回應元素是否存在
在進行值比對之前,應該先檢查預期的鍵是否存在於回應中。可以使用 match contains 來達成此目的:
And match response[0] contains { userId: 1 }
內容解密:
match contains用於檢查回應中是否包含特定的鍵值對。- 可以使用
!contains來檢查某個元素是否不存在於回應中。 - 可以同時比對多個鍵值對。
使用模糊比對器
模糊比對器用於當你不確定值的確切內容,但知道其結構或資料型別時。可以使用特殊的標記(以 # 符號開頭)來檢查不同的條件。例如,檢查某個鍵是否存在:
And match response[0] == { id: '#present', userId: '#present', title: '#present', body: '#present' }
內容解密:
#present標記用於檢查某個鍵是否存在。#notpresent標記用於檢查某個鍵是否不存在。- 其他可用的標記包括
#null、#notnull、#array、#object、#boolean、#number和#string,用於檢查資料型別。
使用斷言和匹配器驗證回應內容
在進行API測試時,驗證回應內容的正確性是非常重要的。Karate提供了一系列強大的工具來幫助我們完成這項任務。
驗證JSON資料
當我們收到JSON格式的回應時,可以使用Karate的匹配器來驗證其內容。例如:
And match response[0] == { id: '#number', userId: '#number', title: '#string', body: '#string' }
這行程式碼檢查了回應的第一個元素是否符合預期的資料型別。
內容解密:
response[0]:存取回應的第一個元素。id: '#number':檢查id欄位是否為數字。userId: '#number':檢查userId欄位是否為數字。title: '#string':檢查title欄位是否為字串。body: '#string':檢查body欄位是否為字串。
如果我們將其中一個欄位的資料型別改為錯誤的型別(例如,id: '#string'),Karate會提供詳細的錯誤訊息,指出哪個欄位出了問題。
選用值
除了檢查欄位是否存在或為特定值外,Karate還允許我們檢查選用值。我們可以在匹配器中使用##來表示一個欄位是選用的。例如:
{ 'userId': '##number', 'id': '##string' }
這表示userId和id欄位是選用的,如果它們存在,則必須符合指定的資料型別。
內容解密:
##number:表示該欄位是選用的數字。- 如果欄位存在,則檢查其資料型別;如果不存在或為空,則忽略檢查。
驗證陣列元素
要驗證陣列中的所有元素,可以使用match each語法。例如:
And match each response == { id: '#number', userId: '#number', title: '#string', body: '#string' }
這行程式碼會檢查回應陣列中的每個元素是否符合預期的資料型別。
內容解密:
match each response:對回應陣列中的每個元素進行匹配檢查。- 後面的JSON物件定義了預期的資料型別。
我們還可以結合contains來驗證陣列元素中特定欄位的值。例如:
And match each response contains { userId: 1 }
這行程式碼檢查每個陣列元素是否包含userId為1的欄位。
內容解密:
match each response contains:檢查每個陣列元素是否包含指定的欄位和值。{ userId: 1 }:定義了預期的欄位和值。
驗證JSON結構
Karate提供了簡便的方法來驗證JSON結構,不需要使用複雜的JSON Schema。
驗證陣列
可以使用#[]標記來驗證回應是否為陣列。例如:
And match response == '#[]'
這行程式碼檢查回應是否為陣列。
內容解密:
#[]:表示預期回應為陣列。
我們還可以指定陣列的大小:
And match response == '#[10]'
這表示預期回應是包含10個元素的陣列。
內容解密:
#[10]:指定陣列的大小為10。
進一步地,我們可以結合多個檢查:
And match response == '#[] #object? _.userId == 1'
這行程式碼結合了多個檢查:
- 回應是陣列嗎?
- 每個陣列元素都有
userId屬性且值為1嗎?
內容解密:
#[]:檢查回應是陣列。#object:檢查陣列元素是物件。? _.userId == 1:檢查每個物件的userId屬性是否為1。
這樣的語法使得我們能夠在單一行中執行多個檢查,大大提高了測試的效率和可讀性。
使用Karate進行基本測試
傳送帶有請求負載的請求
到目前為止,我們只處理了回應資料。但如果是傳送包含請求負載的請求,如POST、PUT和PATCH,該怎麼辦?讓我們來看看JSONPlaceholder API的另一個部分,它允許我們做到這一點。
非永續性模擬API
需要注意的是,JSONPlaceholder API是一個非永續性的API。這意味著無論我們傳送多少次建立或修改資料的請求,其底層資料都不會被改變。它只是模擬了一個真實的API傳回了相應的回應。 這使得它非常適合用於測試。
根據使用者,我們可以看到/posts端點支援POST操作,以建立一個新的文章。
根據檔案,傳送到端點的請求體應該如下所示:
{
"title": "foo",
"body": "bar",
"userId": 1
}
傳回的值應該是建立的文章,包括其ID:
{
"id": 101,
"title": "foo",
"body": "bar",
"userId": 1
}
由於請求體和回應都很簡單,這是一個很好的例子來說明POST請求。
傳送帶有請求負載的請求
讓我們在posts.feature檔案中建立一個新的場景,名為「Creating a new post」,內容如下:
Scenario: Creating a new post
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { userId: 10, title: 'Hello', body: 'World' }
When method post
Then status 201
And match responseType == 'json'
And match response == { id: #number, userId: 10, title: 'Hello', body: 'World' }
使用變數和資料表格
Karate允許將值儲存到變數中,以便在一個測試中多次使用相同的JSON體或值,而不必在多個地方更改它們,如果我們想用不同的值進行測試。資料表格則允許更可讀地定義JSON資料。
使用變數
變數是Karate測試中非常強大的工具。它們可以儲存幾乎任何值型別,因此非常靈活。
要宣告一個簡單的變數,可以使用def關鍵字,表示定義。在下面的例子中,我們將字串「Benjamin」儲存在myName變數中,並在print陳述式中使用它:
Scenario: Declaring a variable
* def myName = 'Benjamin'
* print 'Hello from', myName
執行時,這將輸出Hello from Benjamin,顯示myName的內容符合預期。
將請求負載儲存在變數中
讓我們首先將初始請求負載儲存在一個名為payload的新變數中,並使用它來傳送POST請求:
Scenario: Creating a new post with variable
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
* def payload = { userId: 10, title: 'Hello', body: 'World' }
And request payload
When method post
Then status 201
And match responseType == 'json'
And match response contains payload
程式碼解析:
* def payload = { userId: 10, title: 'Hello', body: 'World' }:定義了一個名為payload的變數,用於儲存請求負載。And request payload:使用定義的payload變數作為請求負載傳送POST請求。And match response contains payload:檢查回應是否包含與payload相同的內容。
重構檢查邏輯
由於我們的API傳回的回應包含一個額外的id欄位,我們需要調整檢查邏輯以匹配回應中的部分內容。
And match response contains { userId: 10, title: 'Hello', body: 'World' }
或者使用之前定義的payload變數:
And match response contains payload
這樣,我們可以確保回應中包含了我們傳送的請求負載內容。
使用 Karate 編寫基本 API 測試
在前一章節中,我們遇到了回應與請求不完全匹配的問題,因為回應中多了一個 id 變數。本章節將介紹幾種解決方案,並探討如何使用 Karate 編寫基本的 API 測試。
簡化回應匹配
我們的 payload 變數持有一個 JSON 物件。因此,我們可以在進行檢查之前,將額外的 id 鍵新增到我們的 JSON 變數中。由於我們知道它應該是一個數字,因此我們也可以使用特殊的 #number 標記。
* payload.id = "#number"
* print payload
And match response == payload
執行測試後,應該會透過並列印出新的 payload 變數:
{
"userId": 10,
"title": "Hello",
"text": "World",
"id": "#number"
}
內容解密:
payload.id = "#number":將id屬性新增到payloadJSON 物件中,並使用#number標記表示它應該是一個數字。print payload:列印修改後的payload變數,以驗證其內容。And match response == payload:將回應與修改後的payload進行匹配,確保它們相同。
使用資料表格
當處理複雜的 JSON 陣列時,使用資料表格可以使測試更具可讀性。
* table numbersAndWords
| number | word |
| 5 | 'five' |
| 10 | 'ten' |
* print numbersAndWords
輸出結果:
[
{
"number": 5,
"word": "five"
},
{
"number": 10,
"word": "ten"
}
]
內容解密:
table numbersAndWords:定義一個名為numbersAndWords的資料表格。- 資料表格的第一行是標頭,定義了 JSON 物件的鍵。
- 後續行被轉換為 JSON 陣列元素,每個元素的鍵來自標頭,值來自對應的行。
使用資料表格建立測試案例
Scenario: 使用資料表格建立新帖子
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
* table payload
| userId | title | text |
| 10 | 'Hello' | 'World' |
* def payload = payload[0]
And request payload
When method post
Then status 201
And match responseType == 'json'
* payload.id = "#number"
And match response == payload
內容解密:
table payload:定義一個名為payload的資料表格,用於建立測試資料。def payload = payload[0]:將payload變數設定為其第一個元素,以便後續使用。- 後續步驟與前面的範例相同,使用修改後的
payload傳送請求並驗證回應。
使用 set 建立測試資料
Scenario: 使用 set 建立新帖子
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
* set payload
| path | 0 |
| userId | 10 |
| title | 'Hello' |
| text | 'World' |
* def payload = payload[0]
And request payload
When method post
Then status 201
And match responseType == 'json'
* payload.id = "#number"
And match response == payload
內容解密:
set payload:使用set語法建立測試資料,鍵在左列,值在右列。- 第一列的標頭必須包含
path,用於指定鍵的路徑。 - 後續步驟與前面的範例相同,使用建立的
payload傳送請求並驗證回應。
在IDE中執行和除錯Karate測試
在本章中,我們將探討如何透過IDE執行和除錯Karate測試。首先,我們將瞭解如何使用Karate CLI執行測試,然後我們將重點放在如何透過IDE進行除錯。
使用Karate CLI執行測試
在之前的章節中,我們使用了Karate CLI來執行測試。這對於簡單的測試觸發是可以的,但是我們希望對測試有更多的控制權。因此,我們不會在這裡使用它。
更多關於Karate CLI功能的資訊可以在https://github.com/karatelabs/karate/wiki/Debug-Server#karate-cli找到。接下來,我們將看看如何直接從IDE除錯測試。
透過CodeLens和Karate standalone除錯
您可能記得,在第2章“設定您的Karate專案”中,我們討論了Karate standalone的基本功能。在本文中,我們將再次使用它來舒適地除錯我們的測試。
如果我們現在嘗試使用CodeLens中的“Karate:除錯”選項,它將無法工作。這是因為缺少兩個關鍵部分:Karate standalone的路徑和啟動組態。
組態Karate standalone
在此步驟中,我們將組態Karate standalone的路徑,以便用於除錯。
- 透過點選右上角的Karate按鈕並選擇“Open Settings”(或透過“File | Preferences | Settings”選單)開啟設定。
- 尋找“Karate Runner > Karate Jar:Command Line Args”條目,並將
karate.jar替換為Karate standalone目錄中karate.jar的完整路徑。
圖4.4 – 組態Karate JAR路徑
如截圖所示,我們的路徑是C:\Users\bbischoff\Desktop\karate-1.2.1.RC1\karate.jar。您的路徑當然會不同,並且可能具有不同的版本號。
重要的是保持命令的其他部分不變。
建立啟動組態
要建立除錯啟動組態,我們可以點選任何測試場景上方的CodeLens中的“Karate:除錯”連結。VS Code將提示我們選擇要使用的偵錯程式。
圖4.5 – 選擇偵錯程式
在這裡,我們選擇了“Karate(debug)”。VS Code現在將建立並開啟位於專案.vscode目錄下的launch.json檔案。該檔案包含一個或多個用於除錯的組態。
圖4.6 – Karate除錯啟動組態
您可以看到,在檔案的組態部分,有一個名為“Karate(debug):Standalone”的組態,表明將使用Karate standalone來執行它。
現在,我們應該能夠透過再次點選“Karate:除錯”CodeLens選項來成功使用它。
使用除錯伺服器
尤其是在測試開發過程中,瞭解測試在特定步驟中的當前狀態、詳細的請求和回應、以及如果選擇其他值會發生什麼是非常有趣的。所有這些都可以使用我們現在擁有的除錯伺服器設定來實作。
設定斷點
您可以在要除錯的Karate場景中設定斷點。這意味著當到達具有斷點的行時,執行將暫停。
要設定斷點,請點選應該發生斷點的行的左側。在這裡,我們在第10行設定了一個斷點,即Then status 200。
圖4.8 – 設定斷點
設定的斷點也將出現在VS Code的左下角,以及檔名、路徑和行號。
圖4.9 – 斷點列表
也可以設定多個斷點,以檢視多個步驟中發生的情況。
讓我們看看現在除錯測試時會發生什麼。
探索當前狀態
點選具有活動斷點的“Karate:除錯”將在到達該行時停止執行。同時,它會被突出顯示以直觀地顯示這一點。
圖4.10 – 到達斷點時突出顯示的行
在VS Code的左側,這也反映在“CALL STACK”部分。
圖4.11 – VS Code呼叫堆積疊
最重要的部分是“VARIABLES”。在這裡,我們可以看到當前步驟中所有相關的變數。
圖4.12 – VS Code斷點變數
在這種情況下,我們看到response JSON、responseHeaders和responseStatus,甚至可以展開它們以檢視完整內容。這使得除錯非常簡單直接。
前後步進
當斷點被觸發且執行停止時,在VS Code的頂部會出現一個新的除錯工具欄。
圖4.13 – 除錯工具欄
// 示例程式碼
public class DebugExample {
public static void main(String[] args) {
// 在這裡設定斷點
int result = add(2, 3);
System.out.println(result);
}
public static int add(int a, int b) {
return a + b;
}
}
內容解密:
此Java程式碼演示了一個簡單的加法運算。首先,在main方法中呼叫add方法,將2和3相加,並將結果儲存在result變數中。然後,列印預出結果。在add方法中,簡單地傳回兩個輸入整數的和。可以在int result = add(2, 3);行設定斷點,以除錯程式並檢視變數的值。