Explorando a estrutura de teste de Jersey
1. Visão geral
Neste tutorial, vamos dar uma olhada na Jersey Test Framework e ver como podemos usá-la para escrever rapidamente testes de integração.
2. Configuração do aplicativo
O Jersey Test Framework é uma ferramenta para nos ajudar a verificar a implementação correta de nossos componentes do servidor. Como veremos mais tarde,it provides a fast and fuss-free way for writing integration testse pode lidar muito bem com a comunicação com nossas APIs HTTP.
Likewise, it works almost out-of-the-box and it’s easy to integrate with our Maven-based projects. A estrutura é baseada principalmente no JUnit, embora também seja possível usar com o TestNG, o que o torna utilizável em quase todos os ambientes.
Na próxima seção, veremos quais dependências precisamos adicionar ao nosso aplicativo para usar o framework.
2.1. Dependências do Maven
Em primeiro lugar, vamos adicionar a dependência principal do Jersey Test Framework ao nossopom.xml:
org.glassfish.jersey.test-framework
jersey-test-framework-core
2.27
test
Como sempre, podemos obter a versão mais recente deMaven Central.
Quase todos os testes de Jersey usam a fábrica de contêineres de teste Grizzly, que também precisamos adicionar:
org.glassfish.jersey.test-framework.providers
jersey-test-framework-provider-grizzly2
2.27
test
Novamente, podemos encontrar a versão mais recente emMaven Central.
3. Começando
Nesta próxima seção, abordaremos as etapas básicas necessárias para escrever um teste simples.
Vamos começar testando o recursoGreetings simples em nosso servidor:
@Path("/greetings")
public class Greetings {
@GET
@Path("/hi")
public String getHiGreeting() {
return "hi";
}
}
3.1. Configurando o Teste
Agora vamos definir nossa classe de teste:
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.
Em seguida, substituímos o métodoconfigure que retorna uma configuração de recurso personalizada para nosso teste e contém apenas o recursoGreetings. Este é, obviamente, o recurso que desejamos testar.
3.2. Escrevendo nosso primeiro teste
Vamos começar testando uma solicitação GET simples da nossa API de saudações:
@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);
}
Observe que temos acesso total à resposta HTTP -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.
Vamos explicar com mais detalhes o que fazemos no exemplo acima:
-
Envie uma solicitação HTTP GET para ‘/ greetings / hi '
-
Verifique o código de status HTTP e os cabeçalhos de resposta do tipo de conteúdo
-
Teste o conteúdo da resposta contém a sequência "oi"
4. Testando GET para recuperar recursos
Agora que vimos as etapas básicas envolvidas na criação de testes. Vamos testar a API Fruit simples que apresentamos no excelenteJersey MVC Support article.
4.1. Obter JSON simples
No exemplo abaixo, estamos trabalhando com o corpo da resposta como uma String JSON padrão:
@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. Obter Entidade em vez de JSON
Também podemos mapear a resposta diretamente para uma classe de entidade Resource - por exemplo:
@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());
}
Desta vez, especificamos o tipo Java para o qual a entidade de resposta será convertida no métodoget - um objetoFruit.
5. Testando POST para criar recursos
Para criar um novo recurso em nossa API - faremos um bom uso das solicitações POST. Na próxima seção, veremos como testar essa parte de nossa API.
5.1. Post Plain JSON
Vamos começar postando uma string JSON simples para testar a criação de um novo recurso de frutas:
@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]"));
}
No exemplo acima, usamos o métodopost que usa um parâmetro de objetoEntity. We use the convenient json method to create an entity from the corresponding JSON string.
5.2. Post Entity em vez de JSON
As we’ve already seen with get requests we can also post a Resource entity class directly - por exemplo:
@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"));
}
Desta vez, usamos o métodoentity para postar nossa entidade Fruit e também especificar o tipo de mídia como JSON.
5.3. Envios de formulários usando POST
Em nosso exemplo final de postagem, veremos como testar os envios de formulários por meio de uma solicitação de postagem:
@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"));
}
Da mesma forma, usamos a classeEntity, mas desta vez passamos um formulário que contém uma série de parâmetros para nossa solicitação de postagem.
6. Teste de outros verbos HTTP
Às vezes, precisamos testar outros pontos de extremidade HTTP, como PUT e DELETE. This is of course perfectly possible using the Jersey Test Framework.
Vejamos um exemplo simples de 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"));
}
Depois de chamar o métodorequest, podemos chamar qualquer método HTTP no objeto de solicitação atual.
7. Características adicionais
A estrutura de teste Jersey contém várias propriedades de configuração adicionais que podem ajudar a depurar e testar.
No próximo exemplo, veremos como habilitar programaticamente um recurso com um determinado nome:
public class FruitResourceIntegrationTest extends JerseyTest {
@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
//...
Quando criamos e configuramos nosso aplicativo Jersey em teste. Também podemos ativar propriedades adicionais. Nesse caso, habilitamos duas propriedades de registro -LOG_TRAFFICeDUMP_ENTITYwhich will provide useful additional logging and debug information during test runs.
8. Recipientes Suportados
Como já mencionamos, o contêiner de fato usado ao escrever testes com o Jersey Test Framework é o Grizzly. However, a number of other containers are supported:
-
Recipiente na memória
-
HttpServer do Oracle JDK
-
Contêiner simples (org.simpleframework.http
-
Contêiner do cais (org.eclipse.jetty)
Para obter mais informações sobre como configurar esses contêineres, consulte a documentaçãohere.
9. Conclusão
Para resumir, neste tutorial, exploramos a estrutura de teste de Jersey. Primeiro, começamos apresentando como configurar o Jersey Test Framework e depois vimos como escrever um teste para uma API muito simples.
Na próxima seção, vimos como escrever testes para uma variedade de pontos de extremidade GET e POST API. Por fim, analisamos alguns recursos adicionais e os contêineres que o Jersey Test Framework suporta.
Como sempre, o código-fonte completo do artigo está disponívelover on GitHub.