REST API Testing with Karate – 用空手道测试REST API

最后修改: 2017年 11月 16日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll introduce Karate, a Behavior Driven Development (BDD) testing framework for Java.

在本文中,我们将介绍Karate,一个用于Java的行为驱动开发(BDD)测试框架。

2. Karate and BDD

2.空手道和BDD

Karate is built on top of Cucumber, another BDD testing framework, and shares some of the same concepts. One of these is the use of a Gherkin file, which describes the tested feature. However, unlike Cucumber, tests aren’t written in Java and are fully described in the Gherkin file.

Karate建立在Cucumber之上,Cucumber是另一个BDD测试框架,并且共享一些相同的概念。其中之一是使用Gherkin文件,该文件描述了所测试的功能。然而,与Cucumber不同的是,测试不是用Java编写的,而是在Gherkin文件中完全描述。

A Gherkin file is saved with the “.feature” extension. It begins with the Feature keyword, followed by the feature name on the same line. It also contains different test scenarios, each beginning with the keyword Scenario and consisting of multiple steps with the keywords Given, When, Then, And, and But.

Gherkin文件的扩展名是”.feature”。它以Feature关键字开始,在同一行中紧跟功能名称。它还包含不同的测试场景,每个场景以关键字Scenario开始,由多个步骤组成,关键字为GivenWhenThenAndBut

More about Cucumber and the Gherkin structure can be found here.

关于Cucumber和Gherkin结构的更多信息可在此处找到。

3. Maven Dependencies

3.Maven的依赖性

To make use of Karate in a Maven project, we need to add the karate-apache dependency to the pom.xml:

为了在Maven项目中使用Karate,我们需要在pom.xml中添加Karate-apache依赖。

<dependency>
    <groupId>com.intuit.karate</groupId>
    <artifactId>karate-apache</artifactId>
    <version>0.6.0</version>
</dependency>

We’ll also need the karate-junit4 dependency to facilitate JUnit testing:

我们还需要karate-junit4依赖,以方便JUnit测试。

<dependency>
    <groupId>com.intuit.karate</groupId>
    <artifactId>karate-junit4</artifactId>
    <version>0.6.0</version>
</dependency>

4. Creating Tests

4.创建测试

We’ll start by writing tests for some common scenarios in a Gherkin Feature file.

我们将首先为Gherkin Feature文件中的一些常见场景编写测试。

4.1. Testing the Status Code

4.1.测试状态代码

Let’s write a scenario that tests a GET endpoint and checks if it returns a 200 (OK) HTTP status code:

让我们写一个场景,测试一个GET端点,并检查它是否返回200(OK)HTTP状态代码。

Scenario: Testing valid GET endpoint
Given url 'http://localhost:8097/user/get'
When method GET
Then status 200

This works obviously with all possible HTTP status codes.

这显然适用于所有可能的HTTP状态代码。

4.2. Testing the Response

4.2.测试响应

Let’s a write another scenario that tests that the REST endpoint returns a specific response:

让我们再写一个场景,测试REST端点是否返回一个特定的响应。

Scenario: Testing the exact response of a GET endpoint
Given url 'http://localhost:8097/user/get'
When method GET
Then status 200
And match $ == {id:"1234",name:"John Smith"}

The match operation is used for the validation where ‘$’ represents the response. So the above scenario checks that the response exactly matches ‘{id:”1234″,name:”John Smith”}’.

match操作被用于验证,其中’$’代表响应。因此,上述方案检查响应是否与’{id: “1234″,name: “John Smith”}’完全匹配。

We can also check specifically for the value of the id field:

我们还可以专门检查id字段的值。

And match $.id == "1234"

The match operation can also be used to check if the response contains certain fields. This is helpful when only certain fields need to be checked or when not all response fields are known:

match操作也可用于检查响应是否包含某些字段。当只需要检查某些字段或不知道所有响应字段时,这很有帮助。

Scenario: Testing that GET response contains specific field
Given url 'http://localhost:8097/user/get'
When method GET
Then status 200
And match $ contains {id:"1234"}

4.3. Validating Response Values With Markers

4.3.用标记物验证响应值

In the case where we don’t know the exact value that is returned, we can still validate the value using markers — placeholders for matching fields in the response.

在我们不知道返回的确切值的情况下,我们仍然可以使用markers(响应中匹配字段的占位符)来验证该值。

For example, we can use a marker to indicate whether we expect a null value or not:

例如,我们可以用一个标记来表明我们是否期待一个null值。

  • #null
  • #notnull

Or we can use a marker to match a certain type of value in a field:

或者我们可以使用一个标记来匹配一个字段中的某种类型的值。

  • #boolean
  • #number
  • #string

Other markers are available for when we expect a field to contain a JSON object or array:

当我们期望一个字段包含一个JSON对象或数组时,可以使用其他标记。

  • #array
  • #object

And there’re markers for matching on a certain format or regular expression and one that evaluates a boolean expression:

还有用于匹配某种格式或正则表达式的标记,以及一个评估布尔表达式的标记。

  • #uuid — value conforms to the UUID format
  • #regex STR — value matches the regular expression STR
  • #? EXPR — asserts that the JavaScript expression EXPR evaluates to true

Finally, if we don’t want any kind of check on a field, we can use the #ignore marker.

最后,如果我们不希望对一个字段进行任何形式的检查,我们可以使用#ignore标记。

Let’s rewrite the above scenario to check that the id field is not null:

让我们重写上述方案,检查id字段是否为null

Scenario: Test GET request exact response
Given url 'http://localhost:8097/user/get'
When method GET
Then status 200
And match $ == {id:"#notnull",name:"John Smith"}

4.4. Testing a POST Endpoint With a Request Body

4.4.用请求正文测试POST端点

Let’s look at a final scenario that tests a POST endpoint and takes a request body:

让我们看看最后一个场景,它测试一个POST端点并接受一个请求体。

Scenario: Testing a POST endpoint with request body
Given url 'http://localhost:8097/user/create'
And request { id: '1234' , name: 'John Smith'}
When method POST
Then status 200
And match $ contains {id:"#notnull"}

5. Running Tests

5.运行测试

Now that the test scenarios are complete, we can run our tests by integrating Karate with JUnit.

现在,测试场景已经完成,我们可以通过将Karate与JUnit集成来运行我们的测试。

We’ll use the @CucumberOptions annotation to specify the exact location of the Feature files:

我们将使用@CucumberOptions注释来指定Feature文件的确切位置。

@RunWith(Karate.class)
@CucumberOptions(features = "classpath:karate")
public class KarateUnitTest {
//...     
}

To demonstrate the REST API, we’ll use a WireMock server.

为了演示REST API,我们将使用一个WireMock服务器。

For this example, we mock all the endpoints that are being tested in the method annotated with @BeforeClass. We’ll shut down the WireMock server in the method annotated with @AfterClass:

在这个例子中,我们在@BeforeClass注解的方法中模拟所有被测试的端点。我们将在@AfterClass注解的方法中关闭WireMock服务器。

private static WireMockServer wireMockServer
  = new WireMockServer(WireMockConfiguration.options().port(8097));

@BeforeClass
public static void setUp() throws Exception {
    wireMockServer.start();
    configureFor("localhost", 8097);
    stubFor(
      get(urlEqualTo("/user/get"))
        .willReturn(aResponse()
          .withStatus(200)
          .withHeader("Content-Type", "application/json")
          .withBody("{ \"id\": \"1234\", name: \"John Smith\" }")));

    stubFor(
      post(urlEqualTo("/user/create"))
        .withHeader("content-type", equalTo("application/json"))
        .withRequestBody(containing("id"))
        .willReturn(aResponse()
          .withStatus(200)
          .withHeader("Content-Type", "application/json")
          .withBody("{ \"id\": \"1234\", name: \"John Smith\" }")));

}

@AfterClass
public static void tearDown() throws Exception {
    wireMockServer.stop();
}

When we run the KarateUnitTest class, the REST Endpoints are created by the WireMock Server, and all the scenarios in the specified feature file are run.

当我们运行KarateUnitTest类时,REST端点由WireMock服务器创建,并运行指定特征文件中的所有场景。

6. Conclusion

6.结论

In this tutorial, we looked at how to test REST APIs using the Karate Testing Framework.

在本教程中,我们研究了如何使用Karate测试框架测试REST APIs。

Complete source code and all code snippets for this article can be found over on GitHub.

本文的完整源代码和所有代码片段都可以在GitHub上找到超过