Проучване на рамката за тестове на Джърси

1. Общ преглед

В този урок ще разгледаме рамката за тестове на Джърси и ще видим как можем да я използваме за бързо писане на тестове за интеграция.

Както вече видяхме в предишни статии, Джърси е рамка с отворен код за разработване на RESTful Web Services . Можем да научим повече за Джърси в нашето въведение в създаването на API с Джърси и пролетта - тук.

2. Настройка на приложението

Тестовата рамка на Джърси е инструмент, който ни помага да проверим правилното изпълнение на нашите сървърни компоненти. Както ще видим по-късно, той осигурява бърз и безпроблемен начин за писане на тестове за интеграция и може да се справи много добре с комуникацията с нашите HTTP API.

По същия начин тя работи почти нестандартно и е лесно да се интегрира с нашите проекти, базирани на Maven . Рамката се основава предимно на JUnit, въпреки че е възможно да се използва и с TestNG, което я прави използваема в почти всички среди.

В следващия раздел ще видим кои зависимости трябва да добавим към нашето приложение, за да използваме рамката.

2.1. Зависимости на Maven

Първо, нека добавим основната зависимост на Jersey Test Framework към нашия pom.xml :

 org.glassfish.jersey.test-framework jersey-test-framework-core 2.27 test 

Както винаги, можем да получим най-новата версия от Maven Central.

Почти почти всички тестове в Джърси използват фабриката за тестови контейнери defacto Grizzly, която също ще трябва да добавим:

 org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-grizzly2 2.27 test 

Отново можем да намерим най-новата версия в Maven Central.

3. Първи стъпки

В този следващ раздел ще разгледаме основните стъпки, необходими за написването на прост тест.

Ще започнем с тестване на простия ресурс за поздрави на нашия сървър:

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

3.1. Конфигуриране на теста

Сега нека дефинираме нашия тестов клас:

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

В горния пример можем да видим, че за да разработим тест с помощта на Jersey Test Framework, нашият тест трябва да подкласира JerseyTest .

След това заместваме метода за конфигуриране , който връща персонализирана конфигурация на ресурса за нашия тест и съдържа само ресурса Поздрави . Това, разбира се, е ресурсът, който искаме да тестваме.

3.2. Писане на първия ни тест

Нека започнем с тестване на проста GET заявка от нашия API за поздрави:

@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); } 

Забележете, че имаме пълен достъп до HTTP отговора - за да можем да правим неща като проверка на кода на състоянието, за да се уверим, че операцията е била действително успешна, или да работим с действителното тяло на отговора .

Нека да обясним по-подробно какво правим в горния пример:

  1. Изпратете HTTP GET заявка до „/ greetings / hi“
  2. Проверете кода на състоянието HTTP и заглавките за отговор на типа съдържание
  3. Тествайте съдържанието на отговора, съдържащ низа „hi“

4. Тестване на GET за извличане на ресурси

Сега, след като видяхме основните стъпки, свързани със създаването на тестове. Нека тестваме простия API за плодове, който въведохме в отличната статия за поддръжка на Jersey MVC.

4.1. Вземете обикновен JSON

В примера по-долу работим с тялото на отговора като стандартен JSON String:

@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. Вземете Entity вместо JSON

Също така можем да картографираме отговора директно към клас на обект Resource - например:

 @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()); }

Този път посочваме типа Java, в който обектът за отговор ще бъде преобразуван в метода get - обект Fruit .

5. Тестване на POST за създаване на ресурси

За да създадем нов ресурс в нашия API - ще използваме добре POST заявките. В следващия раздел ще видим как да тестваме тази част от нашия API.

5.1. Post Plain JSON

Нека започнем с публикуване на обикновен JSON String, за да тестваме създаването на нов плодов ресурс:

@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]")); }

В горния пример използваме метода post , който приема параметър Entity object. Използваме удобния метод json , за да създадем обект от съответния JSON низ .

5.2. Post Entity Instead of 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.

5.3. Form Submissions Using 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.

6. Testing Other HTTP Verbs

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

Let's see a simple PUT example:

@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.

7. Additional Features

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

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_ENTITYwhich will provide useful additional logging and debug information during test runs.

8. Supported Containers

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:

  • 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

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.

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.

Както винаги, пълният изходен код на статията е достъпен в GitHub.