Exploring the Jersey Test Framework – 探索泽西岛测试框架

最后修改: 2018年 10月 15日

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

1. Overview

1.概述

In this tutorial, we’re going to take a look at the Jersey Test Framework and see how we can use it to quickly write integration tests.

在本教程中,我们要看一下Jersey测试框架,看看我们如何使用它来快速编写集成测试。

As we’ve already seen in previous articles, Jersey is an open source framework for developing RESTful Web Services. We can learn more about Jersey in our introduction to creating an API with Jersey and Spring article – here.

正如我们在以前的文章中已经看到的,Jersey是一个用于开发RESTful Web服务的开源框架。我们可以在介绍使用Jersey和Spring创建API的文章中了解更多关于Jersey的信息 – 这里

2. Application Setup

2.应用程序的设置

The Jersey Test Framework is a tool to help us verify the correct implementation of our server-side components. As we’ll see later, it provides a fast and fuss-free way for writing integration tests and can handle communicating with our HTTP APIs very well.

Jersey测试框架是一个工具,可以帮助我们验证服务器端组件的正确实现。正如我们稍后所见,它为编写集成测试提供了一种快速和无忧无虑的方式,并能很好地处理与我们的HTTP APIs的通信。

Likewise, it works almost out-of-the-box and it’s easy to integrate with our Maven-based projects. The framework is primarily based on JUnit although it is possible to use with TestNG as well which makes it usable in almost all environments.

同样,它几乎是开箱即用,很容易与我们基于Maven的项目集成。该框架主要基于JUnit,尽管它也可以与TestNG一起使用,这使得它几乎可以在所有环境中使用。

In the next section, we’ll see which dependencies we need to add to our application in order to use the framework.

在下一节中,我们将看到为了使用该框架,我们需要向我们的应用程序添加哪些依赖项。

2.1. Maven Dependencies

2.1.Maven的依赖性

First of all, let’s add the Jersey Test Framework core dependency to our pom.xml:

首先,让我们把Jersey Test Framework的核心依赖关系添加到我们的pom.xml

<dependency>
    <groupId>org.glassfish.jersey.test-framework</groupId>
    <artifactId>jersey-test-framework-core</artifactId>
    <version>2.27</version>
    <scope>test</scope>
</dependency>

As always, we can get the latest version from Maven Central.

一如既往,我们可以从Maven Central获得最新版本。

Nearly almost all Jersey tests use the defacto Grizzly test container factory, which we will also need to add:

几乎所有的泽西岛测试都使用默认的Grizzly测试容器工厂,我们也需要添加它。

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.27</version>
    <scope>test</scope>
</dependency>

Again we can find the latest version in Maven Central.

同样,我们可以在Maven中心找到最新版本。

3. Getting Started

3.入门

In this next section, we’ll cover the basic steps needed to write a simple test.

在下一节中,我们将介绍编写一个简单测试所需的基本步骤。

We’re going to begin by testing the simple Greetings resource on our server:

我们将首先在我们的服务器上测试简单的Greetings资源。

@Path("/greetings")
public class Greetings {

    @GET
    @Path("/hi")
    public String getHiGreeting() {
        return "hi";
    }
}

3.1. Configuring the Test

3.1.配置测试

Now let’s define our test class:

现在让我们来定义我们的测试类。

public class GreetingsResourceIntegrationTest extends JerseyTest {

    @Override
    protected Application configure() {
        return new ResourceConfig(Greetings.class);
    }
    //...
}

We can see in the above example that to develop a test using the Jersey Test Framework our test needs to subclass JerseyTest.

我们可以在上面的例子中看到,要使用Jersey测试框架开发一个测试,我们的测试需要子类化JerseyTest

Next, we override the configure method which returns a custom resource configuration for our test and only contains the Greetings resource. This is, of course, the resource that we wish to test.

接下来,我们覆盖configure方法,它为我们的测试返回一个自定义的资源配置,只包含Greetings资源。当然,这就是我们希望测试的资源。

3.2. Writing Our First Test

3.2.编写我们的第一个测试

Let’s start by testing a simple GET request from our greetings API:

让我们先从我们的问候语API中测试一个简单的GET请求。

@Test
public void givenGetHiGreeting_whenCorrectRequest_thenResponseIsOkAndContainsHi() {
    Response response = target("/greetings/hi").request()
        .get();

    assertEquals("Http Response should be 200: ", Status.OK.getStatusCode(), response.getStatus());
    assertEquals("Http Content-Type should be: ", MediaType.TEXT_HTML, response.getHeaderString(HttpHeaders.CONTENT_TYPE));

    String content = response.readEntity(String.class);
    assertEquals("Content of ressponse is: ", "hi", content);
}

Notice that we have full access to the HTTP response – so we can do things like checking the status code to make sure the operation was actually successful, or work with the actual body of the response.

请注意,我们可以完全访问HTTP响应–所以我们可以做一些事情,比如检查状态代码以确保操作确实成功,或者使用响应的实际主体

Let’s explain in more detail what we do in the above example:

让我们更详细地解释一下我们在上面的例子中做了什么。

  1. Send an HTTP GET request to ‘/greetings/hi’
  2. Check the HTTP status code and content type response headers
  3. Test the contents of the response contains the string “hi”

4. Testing GET to Retrieve Resources

4.测试GET检索资源

Now, that we’ve seen the basic steps involved in creating tests. Let’s test the simple Fruit API that we introduced in the excellent Jersey MVC Support article.

现在,我们已经看到了创建测试的基本步骤。让我们来测试一下我们在优秀的Jersey MVC支持文章中介绍的简单Fruit API。

4.1. Get Plain JSON

4.1.获取普通的JSON

In the below example we’re working with the response body as a standard JSON String:

在下面的例子中,我们把响应体作为一个标准的JSON字符串进行处理。

@Test
public void givenFruitExists_whenSearching_thenResponseContainsFruit() {
    final String json = target("fruit/search/strawberry").request()
        .get(String.class);
    assertThat(json, containsString("{\"name\":\"strawberry\",\"weight\":20}"));
}

4.2. Get Entity Instead of JSON

4.2.获取实体而不是JSON

We can also map the response directly to a Resource entity class – for example:

我们也可以直接将响应映射到资源实体类–例如。

   @Test
    public void givenFruitExists_whenSearching_thenResponseContainsFruitEntity() {
        final Fruit entity = target("fruit/search/strawberry").request()
            .get(Fruit.class);

        assertEquals("Fruit name: ", "strawberry", entity.getName());
        assertEquals("Fruit weight: ", Integer.valueOf(20), entity.getWeight());
    }

This time, we specify the Java type the response entity will be converted to in the get method – a Fruit object.

这一次,我们在get方法中指定响应实体将被转换成的Java类型–Fruit对象。

5. Testing POST to Create Resources

5.测试POST以创建资源

In order to create a new Resource in our API – we will make good use of POST requests. In the next section, we’ll see how to test this part of our API.

为了在我们的API中创建一个新的资源–我们将很好地利用POST请求。在下一节,我们将看到如何测试我们API的这一部分。

5.1. Post Plain JSON

5.1.发布普通的JSON

Let’s start by posting a plain JSON String to test the creation of a new fruit resource:

让我们先发布一个普通的JSON字符串来测试创建一个新的水果资源。

@Test
public void givenCreateFruit_whenJsonIsCorrect_thenResponseCodeIsCreated() {
    Response response = target("fruit/created").request()
        .post(Entity.json("{\"name\":\"strawberry\",\"weight\":20}"));

    assertEquals("Http Response should be 201 ", Status.CREATED.getStatusCode(), response.getStatus());
    assertThat(response.readEntity(String.class), containsString("Fruit saved : Fruit [name: strawberry colour: null]"));
}

In the above example, we make use of the post method which takes an Entity object parameter. We use the convenient json method to create an entity from the corresponding JSON string.

在上面的例子中,我们利用了post方法,它需要一个Entity对象参数。我们使用方便的json方法,从相应的JSON字符串中创建一个实体

5.2. Post Entity Instead of JSON

5.2.发布实体而不是JSON

As we’ve already seen with get requests we can also post a Resource entity class directly – for example:

正如我们已经看到的获取请求,我们也可以直接发布一个资源实体类–例如。

@Test
public void givenCreateFruit_whenFruitIsInvalid_thenResponseCodeIsBadRequest() {
    Fruit fruit = new Fruit("Blueberry", "purple");
    fruit.setWeight(1);

    Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE)
        .post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE));

    assertEquals("Http Response should be 400 ", 400, response.getStatus());
    assertThat(response.readEntity(String.class), containsString("Fruit weight must be 10 or greater"));
}

This time we use the entity method to post our Fruit entity and also specify the media type as JSON.

这次我们使用entity方法来发布我们的Fruit实体,同时指定媒体类型为JSON。

5.3. Form Submissions Using POST

5.3.使用POST的表单提交

In our final post example we will see how to test form submissions via a post request:

在我们最后一个帖子的例子中,我们将看到如何通过帖子请求来测试表单提交。

@Test
public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() {
    Form form = new Form();
    form.param("name", "apple");
    form.param("colour", null);
    
    Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED)
        .post(Entity.form(form));

    assertEquals("Http Response should be 400 ", 400, response.getStatus());
    assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null"));
 }

Similarly, we make use of the Entity class but this time pass a form which contains a number of parameters to our post request.

同样地,我们利用Entity类,但这次是将一个包含一些参数的表单传递给我们的post请求。

6. Testing Other HTTP Verbs

6.测试其他HTTP动词

Sometimes we need to test other HTTP endpoints such as PUT and DELETE. This is of course perfectly possible using the Jersey Test Framework.

有时我们需要测试其他的HTTP端点,如PUT和DELETE。这当然完全可以使用Jersey测试框架。

Let’s see a simple PUT example:

让我们看看一个简单的PUT例子。

@Test
public void givenUpdateFruit_whenFormContainsBadSerialParam_thenResponseCodeIsBadRequest() {
    Form form = new Form();
    form.param("serial", "2345-2345");

    Response response = target("fruit/update").request(MediaType.APPLICATION_FORM_URLENCODED)
        .put(Entity.form(form));

    assertEquals("Http Response should be 400 ", 400, response.getStatus());
    assertThat(response.readEntity(String.class), containsString("Fruit serial number is not valid"));
}

Once we have called the request method, we can invoke any HTTP method on the current request object.

一旦我们调用了request方法,我们就可以对当前请求对象调用任何HTTP方法。

7. Additional Features

7.附加功能[/strong

The Jersey test framework contains a number of additional configuration properties which can help aid debugging and testing.

Jersey测试框架包含一些额外的配置属性,可以帮助调试和测试。

In the next example we’ll see how to programmatically enable a feature with a given name:

在下一个例子中,我们将看到如何以编程方式启用一个给定名称的功能。

public class FruitResourceIntegrationTest extends JerseyTest {

    @Override
    protected Application configure() {
        enable(TestProperties.LOG_TRAFFIC);
        enable(TestProperties.DUMP_ENTITY);
        //...

When we create and configure our Jersey application under test. We can also enable additional properties. In this case, we enable two logging properties – LOG_TRAFFIC and DUMP_ENTITY which will provide useful additional logging and debug information during test runs.

当我们在测试中创建和配置我们的Jersey应用程序时。我们还可以启用其他属性。在这种情况下,我们启用两个日志属性 – LOG_TRAFFICDUMP_ENTITY 这将在测试运行期间提供有用的额外日志和调试信息。

8. Supported Containers

8.支持的容器

As we’ve already mentioned the defacto container used when writing tests with the Jersey Test Framework is Grizzly. However, a number of other containers are supported:

正如我们已经提到的,用Jersey测试框架编写测试时使用的默认容器是Grizzly。但是,也支持一些其他的容器:

  • In-Memory container
  • HttpServer from Oracle JDK
  • Simple container (org.simpleframework.http
  • Jetty container (org.eclipse.jetty)

For more information on how to configure these containers, please see the documentation here.

关于如何配置这些容器的更多信息,请参见文档这里

9. Conclusion

9.结论

To summarize, in this tutorial, we’ve explored the Jersey Test Framework. First, we started by introducing how to configure the Jersey Test Framework and then we saw how to write a test for a very simple API.

总结一下,在本教程中,我们已经探索了Jersey测试框架。首先,我们首先介绍了如何配置Jersey测试框架,然后我们看到了如何为一个非常简单的API写一个测试。

In the next section, we saw how to write tests for a variety of GET and POST API endpoints. Finally, we looked at some additional features and the containers that the Jersey Test Framework supports.

在下一节,我们看到了如何为各种GET和POST API端点编写测试。最后,我们看了一些额外的功能和Jersey测试框架所支持的容器。

As always, the full source code of the article is available over on GitHub.

一如既往,文章的完整源代码可在GitHub上获得