Karate 測試框架根據 Cucumber 但又有所不同,它提供簡潔的 Gherkin 語法和豐富的功能,讓開發者能有效撰寫 API 測試案例。Karate 的 GivenWhenThen 關鍵字與 Cucumber 類別似,但更著重於技術細節的描述,允許在步驟中直接使用 JavaScript 和 JSONPath 等技術。不同於 Cucumber 需要撰寫大量的膠水程式碼(Glue Code),Karate 內建許多常用的步驟和函式,簡化了測試的開發流程。此外,Karate 原生支援 JSON、XML、YAML 等多種資料格式,方便處理不同型別的 API 請求和回應。其 JavaScript 引擎和 Java 互操作性,讓開發者能靈活運用兩種語言的優勢,提升測試效率。設定 Karate 專案也相當簡單,只需安裝 JDK、Maven 和選擇合適的 IDE 即可開始撰寫測試。

介紹Karate的核心概念

When關鍵字

任何與被測系統的互動或更改都以When關鍵字開始。When I search for 'Packt'清楚地描述了使用者做了什麼以及他們的意圖是什麼,但並沒有在技術層面上描述網上商店如何處理這件事。稍後,我們將看到Karate如何彎曲這個核心BDD規則以及為什麼這樣做。

Then關鍵字

大多數測試場景的最後一部分是一個或多個斷言,用於驗證被測系統的某種結果或狀態。這透過Then表達,如Then I get a list of items containing 'Packt'。同樣,這清楚地說明瞭系統預期的結果,但沒有說明應用程式如何確切地解決這個問題。

And關鍵字

And關鍵字可以根據是否有多個前提條件、動作或斷言來連線多個GivenWhenThen行。它只是“語法糖”,使場景更具可讀性。在我們的例子中,它連線了兩個Given陳述式:

  • 使用者在首頁
  • 使用者已登入

But關鍵字

And一樣,But關鍵字可以用來連線步驟。它不像其對應物那麼常見,但可以更好地表達某些條件。例如:

Given I am on the Web shop homepage
And I am not logged in

也可以表述如下:

Given I am on the Web shop homepage
But I am not logged in

這將進一步強調該測試的重點是未授權的使用者。

內容解密:

  • AndBut都是用來連線多個步驟的關鍵字。
  • And用於連線多個相同型別的步驟,如多個前提條件或多個斷言。
  • But用於連線具有對比關係的步驟,使場景更具可讀性。

萬能步驟(*)

Gherkin有一個步驟關鍵字,可以替代所有不同的步驟型別(GivenWhenThenAndBut)。*步驟主要用於當它不符合自然流程時,而是包含實用功能或設定程式碼,或有助於除錯測試場景。

例如,Karate的print函式會在命令列上記錄一個字串,用於簡單地跟蹤值:

* print "The value of my variable is", myVariable

這裡,它並不直接參與任何被測試行為的部分。相反,它可以被視為一個實用步驟,仍然必須遵循事件的時間順序,但可以輕易地與它們分開而不影響整體測試功能。在Karate中,這些要點可以在生成的測試報告中被抑制。

內容解密:

  • *步驟用於包含實用功能或設定程式碼,或有助於除錯測試場景。
  • Karate的print函式用於在命令列上記錄一個字串,用於簡單地跟蹤值。

註解

註解可以用來使某些步驟更清晰,特別是當它們包含新團隊成員或不熟悉被測試業務領域的同事難以理解的資訊時。 此外,它們可以用於臨時停用測試,以進一步解釋為什麼這樣做或在再次啟動之前需要發生什麼。 註解可以放在Gherkin檔案的任何位置。它們以#符號開頭(就像例子中的# This is an example comment line),並且被Cucumber和Karate忽略。

內容解密:

  • 註解用於使某些步驟更清晰或臨時停用測試。
  • 註解以#符號開頭,並被Cucumber和Karate忽略。

BDD與Karate的比較

編寫良好的BDD場景

在進行BDD時,測試場景通常應具有以下特徵,以保持它們在測試套件中的清晰、易懂和簡潔:

  • 場景應該能夠獨立執行:這很重要,因為取決於是否執行所有或只是部分場景,或者它們是否同時在多個執行緒中執行,我們不能總是確定執行的順序。
  • 場景應該簡潔易懂:您的場景不應執行太多步驟,即使Gherkin格式適合於測試案例的易於理解。
  • 場景不應同時測試太多不同的事情:這一點與第二點密切相關——可理解性。通常,場景一旦某一步驟失敗就會失敗,跳過所有後續步驟。
  • 場景不應重複其他場景:在許多情況下,重複進行相同的測試可能沒有意義。
  • 場景不應包含具體的技術資訊:在編寫行為驅動的測試時,重點是高層次的行為以及如何與系統互動。

內容解密:

  • 編寫良好的BDD場景應該能夠獨立執行、簡潔易懂、不重複其他場景、不包含具體的技術資訊。
  • 這些特徵對於保持測試套件的清晰、易懂和簡潔非常重要。

Karate不是真正的BDD

幾乎所有這些觀點都是編寫良好的Karate測試的有效提示。然而,最後一個指導原則(“場景不應包含具體的技術資訊”)是我們稍後將在本章中重新審視的。Karate的想法在這方面是完全不同的,我們將看到為什麼這樣做是有意義的,以及為什麼該框架已經完全脫離了BDD。

BDD 與 Karate 的比較

連執行緒式碼(Glue Code)

所謂的連執行緒式碼(Glue Code)是建立 Gherkin 步驟與具體測試程式碼實作之間的橋樑。這樣,測試框架就可以執行與相應步驟相匹配的函式,包括傳遞的引數。

讓我們來看看這個場景的一部分範例實作: Given I am on the Web shop homepage When I search for ‘Packt’

首先,我們將看看 Cucumber 如何處理連執行緒式碼,以便我們稍後可以更好地將其與 Karate 的方法進行比較。

Cucumber 連執行緒式碼

根據 Cucumber 的框架的一般機制是透過將步驟名稱與預定義的 Cucumber 表示式(Cucumber Expressions)相匹配來工作的,這些表示式透過註解分配給特定的 Java 函式。在舊版本的 Cucumber 中,步驟與連執行緒式碼的匹配是透過正規表示式(Regular Expressions)完成的,但 Cucumber 表示式被證明在自己實作連執行緒式碼時更容易使用:

Package blog.softwaretester.gherkin;

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class StepDefinitions {
    @Given("I am on the Web shop homepage")
    public void goToHomepage() {
        System.out.println("Go to homepage");
    }

    @When("I search for {string}")
    public void search(final String searchTerm) {
        System.out.println("Search for " + searchTerm);
    }
}

內容解密:

  • @Given@When 註解用於將 Gherkin 步驟與 Java 函式相匹配。
  • goToHomepage() 函式在 Cucumber 碰到與 @Given("I am on the Web shop homepage") 註解相匹配的步驟定義時被呼叫。
  • search(final String searchTerm) 函式透過 @When("I search for {string}") 註解與步驟相連線,並接受一個動態引數 searchTerm

Karate 的方式

Karate 使用與 Cucumber 基本相同的機制和概念,但有一些有趣的差異。Karate 直到版本 0.9.0 為止都是根據 Cucumber 的,但後來決定分離出來並保持完全相容。

Karate 連執行緒式碼

Karate 在框架內部直接提供了常見的預定義步驟和相應的連執行緒式碼,這意味著在許多情況下您不需要編寫任何程式碼,因為所需的步驟已經實作好了。

* print "The value of my variable is", myVariable

內容解密:

  • Karate 的 print 陳述式可以直接在測試中使用,用於輸出變數的值。
  • Karate 的內部實作允許使用包含 JavaScript、JSONPath 或 XPath 表示式、Java 函式呼叫等的步驟。

為什麼 Karate 分離自 Cucumber

Karate 分離自 Cucumber 的主要原因是為了擺脫對 Cucumber 時間表、優先順序和功能集的依賴,從而能夠以更快的速度進行開發。由於 Karate 只支援一種程式語言,因此在開發速度上具有優勢。此外,這種舉動使 Karate 能夠控制測試生命週期的所有階段,包括報告,而不受限於現有的 Cucumber 基礎設施、規格和技術。

Karate 的核心概念與資料型別支援

Karate 是一個強大的測試框架,其設計理念源自 Cucumber,但也具備自己的獨特特點。在 Karate 的 ScenarioActions 類別中,我們可以看到以下程式碼,展示瞭如何將前面的場景步驟與膠水程式碼(glue code)連線起來:

@Override
@When("^print (.+)")
public void print(String exp) {
    engine.print(exp);
}

內容解密:

  1. @Override 註解:表示此方法覆寫了父類別中的方法,確保了 Karate 的特定實作能夠正確執行。
  2. @When 註解:使用了正規表示式(regular expression)來匹配特定的步驟,這與 Cucumber 的表示式類別似,但更具彈性。"^print (.+)" 表示匹配以 print 開頭的句子,並將後續內容作為引數傳遞。
  3. engine.print(exp):將捕捉的引數傳遞給 Karate 的內部 print 方法,用於輸出除錯資訊或其他自定義內容。

Karate 對多種資料型別的支援

Karate 的一大優勢在於它原生支援多種常見的資料格式,這使得測試 API 時能夠更靈活地處理不同型別的請求和回應資料。

JSON

JSON 是 REST API 和 GraphQL 中最常用的資料交換格式。以下是一個簡單的 JSON 範例,展示瞭如何巢狀表示鍵值對和陣列:

{
  "book": {
    "title": "Writing tests with Karate",
    "author": "Benjamin Bischoff",
    "chapters": [
      {
        "number": "1",
        "title": "Karate's core concepts"
      }
    ]
  }
}

GraphQL

GraphQL 是由 Facebook 開發並於 2015 年發布的查詢語言。其請求和回應格式均為 JSON,但與 REST API 不同的是,使用者可以精確定義所需資料,從而減少頻寬消耗。以下是一個 GraphQL 回應範例:

{
  "data": {
    "book": {
      "title": "Writing tests with Karate",
      "author": "Benjamin Bischoff",
      "chapters": [
        {
          "number": "1",
          "title": "Karate's core concepts"
        }
      ]
    }
  }
}

XML

XML 是另一種人類可讀的資料格式,儘管它比 JSON 更冗餘。Karate 能夠很好地處理 XML 資料:

<?xml version="1.0" encoding="UTF-8"?>
<book>
  <title>Writing tests with Karate</title>
  <author>Benjamin Bischoff</author>
  <chapters>
    <chapter>
      <number>1</number>
      <title>Karate's core concepts</title>
    </chapter>
  </chapters>
</book>

YAML

YAML 是一種極簡的、根據縮排的語法格式,主要用於設定檔。Karate 能夠自動將 YAML 轉換為 JSON,使其易於在測試中使用:

---
book:
  title: Writing tests with Karate
  author: Benjamin Bischoff
  chapters:
    - number: 1
      title: Karate's core concepts

CSV

CSV(逗號分隔值)是一種常見的資料交換格式,用於儲存表格資料。Karate 能夠自動將 CSV 轉換為 JSON 陣列:

title,author,chapter/number,chapter/title
Writing tests with Karate,Benjamin Bischoff,1,Karate's core concepts

其他資料格式的支援

除了上述格式,Karate 還支援其他文字型資料格式。對於非原生支援的格式,可以使用 Java 或 JavaScript 自訂處理邏輯。此外,Karate 的 Java 互操作性使其能夠處理幾乎任何二進位檔案格式,並提供了專門的 bytes 型別來轉換二進位資料。

Karate 框架的核心概念與專案設定

Karate 的 JavaScript 引擎

Karate 的 JavaScript 引擎是其與眾不同的關鍵之一,根據 GraalVM 建構,支援多語言混編,能夠在單一應用程式中混合使用不同的程式語言,甚至傳遞值。這使得測試作者能夠直接在功能檔案中嵌入原生 JavaScript 程式碼,無論是在 Karate 的主要組態中還是在外部檔案中。

JavaScript 在處理 JSON 格式時非常方便,因為 JSON 是 JavaScript 的原生格式,而在 Java 中則需要額外的函式庫(如 Gson 或 Jackson)。這使得測試作者可以直接在步驟中寫入 JSON,無需轉義或編碼特定字元。同時,JSONPath 的直接整合也使得斷言和匹配更加簡單。

Java 互操作性

儘管 Karate 與 JavaScript 緊密相關,但它完全由 Java 編寫,這確保了其執行速度快、程式碼簡潔,並能在幾乎任何本地系統、CI/CD 伺服器和雲端環境中執行。Java 提供了成熟的開發工具、擴充功能和函式庫,能夠實作快速開發。

Karate 能夠直接呼叫 Java 方法和工具,使得其功能非常強大且易於擴充。透過 JavaScript 呼叫 Java 方法,這是 Karate 的一大特色。

設定您的 Karate 專案

Karate 可以以多種方式使用。我們可以使用其獨立版本來執行測試並嘗試其功能。然而,將其與適當的建置工具和整合開發環境(IDE)結合使用會更方便,因為這大大簡化了開發過程,並促進了測試的執行和除錯。

技術需求

設定 Karate 專案的需求

您需要以下內容:

  • Java 開發套件(JDK)版本 8 或更高版本來開發和執行測試。
  • Maven 來管理 Karate 專案的依賴關係(也可以使用 Gradle,但本文主要使用 Maven)。
  • Visual Studio Code 或 IntelliJ IDEA 作為 IDE(本文使用 Visual Studio Code,因為它有專門的免費 Karate 外掛程式,具有許多實用功能)。
  • Chrome 瀏覽器來嘗試稍後的網頁 UI 自動化範例。

安裝 Java

要開發 Karate 測試,系統上安裝 JDK 是有益的。這不僅允許執行測試,還允許建立和編譯 Java 程式。無論使用何種 IDE,這都是有效 Karate 開發的關鍵元件。

您可以從 Oracle 網站 下載適用於您系統的 Java。

SDKMAN!

對於根據 Unix 的系統,SDKMAN! 是一個安裝 JDK、Maven 或 Gradle 的好選擇。它設定必要的系統環境變數,甚至允許安裝多個版本並在它們之間切換。您可以從 SDKMAN! 網站 瞭解更多。

使用 Maven 設定 Karate 專案

Maven 是管理 Karate 專案依賴關係的優秀工具。本章稍後將討論如何使用 Maven 安裝和設定 Karate 專案。

IDE 的準備

我們將使用 Visual Studio Code 作為主要的 IDE,因為它具有專門為 Karate 設計的免費外掛程式,具有許多有用的功能。

不同作業系統的差異

Karate 能夠在所有主要作業系統上執行。後續步驟大致相似。最大的差異在於程式的安裝方式,以及 Linux 和 macOS 使用終端機,而 Windows 使用命令提示字元或 PowerShell 視窗。

程式碼範例

// Java 程式碼範例
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

內容解密:

此 Java 程式碼定義了一個名為 HelloWorld 的類別,其中包含一個 main 方法,當執行該程式時,會列印出 “Hello, World!"。這個範例展示了 Java 程式的基本結構,包括類別定義、方法定義和輸出陳述式。

// JavaScript 程式碼範例
const jsonData = { name: "John", age: 30 };
console.log(jsonData.name);

內容解密:

此 JavaScript 程式碼定義了一個名為 jsonData 的 JSON 物件,並存取其 name 屬性,將其值列印到控制檯。這個範例展示瞭如何在 JavaScript 中建立和操作 JSON 資料。JSON 是 JavaScript 的原生格式,因此處理起來非常方便。