Pergunta

Atualmente estou procurando maneiras de criar testes automatizados por um JAX-RS (API Java para RESTful web Services) serviço baseado na web.

Basicamente, eu preciso de uma maneira de enviá-lo certas entradas e verificar se eu recebo as respostas esperadas. Eu prefiro fazer isso através JUnit, mas não tenho certeza de como isso pode ser alcançado.

O que se aproximam você usa para testar seus web-services?

Update: Como entzik apontou, dissociando o serviço Web a partir da lógica de negócios me permite unidade de teste a lógica de negócios. No entanto, eu também quero teste para os códigos de status HTTP corretos etc.

Foi útil?

Solução

Jersey vem com um grande cliente API RESTful que torna a escrever testes de unidade muito fácil. Veja os testes de unidade nos exemplos que acompanham Jersey. Nós usamos esta abordagem para testar o suporte a REST em Apache Camel , se você estiver interessado a casos de teste "noreferrer" está aqui

Outras dicas

Você pode experimentar RESTO Assured que torna muito simples de serviços REST de teste e validação da resposta em Java (usando JUnit ou TestNG).

Como James disse; Há built-in teste estrutura para Jersey. Um exemplo do mundo simples Olá pode ser assim:

pom.xml para a integração Maven. Quando você executa mvn test. Estruturas iniciar um recipiente de urso. Você pode usar o cais ou tomcat via mudando dependências.

...
<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.16</version>
  </dependency>

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

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

ExampleApp.java

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class ExampleApp extends Application {

}

HelloWorld.java

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/")
public final class HelloWorld {

    @GET
    @Path("/hello")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHelloWorld() {

        return "Hello World!";
    }
}

HelloWorldTest.java

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.core.Application;
import static org.junit.Assert.assertEquals;

public class HelloWorldTest extends JerseyTest {

    @Test
    public void testSayHello() {

        final String hello = target("hello").request().get(String.class);

        assertEquals("Hello World!", hello);
    }

    @Override
    protected Application configure() {

        return new ResourceConfig(HelloWorld.class);
    }
}

Você pode verificar este aplicativo de exemplo .

Você provavelmente escreveu algum código Java que implementa a lógica de negócios e depois de ter gerado o ponto final de serviços web para isso.

Uma coisa importante a fazer é testar independentemente sua lógica de negócio. Desde que é código java puro você pode fazer isso com testes JUnit regulares.

Agora, uma vez que a parte de serviços web é apenas um ponto final, o que você quer ter a certeza é que o encanamento gerado (tocos, etc) estão em sincronia com o seu código java. você pode fazer isso escrevendo testes JUnit que invocam os clientes Java serviço da Web gerado. Isso vai deixar você saber quando você mudar suas assinaturas java sem atualizar o material serviços web.

Se seu encanamento serviços web é gerado automaticamente pelo seu sistema de construção em cada compilação, em seguida, pode não ser necessário testar os pontos finais (assumindo que está tudo corretamente gerado). Depende do seu nível de paranóia.

Eu uso HTTPClient (http://hc.apache.org/) do Apache para chamar Restful Serviços . A biblioteca cliente HTTP permite que você execute facilmente obter, pós ou qualquer outra operação que você precisa. Se o serviço usa JAXB para a ligação xml, você pode criar um JAXBContext às entradas serializar e desserializar e saídas a partir da solicitação HTTP.

Dê uma olhada Alchemy cliente resto gerador . Isso pode gerar uma implementação proxy para seus JAX-RS webservice classe usando o cliente de camisa por trás da cena. Efetivamente você vai chamá-lo webservice métodos como métodos Java simples de seus testes de unidade. Alças http autenticação bem.

Não há geração de código envolvido se você precisará testes simplesmente executados por isso é conveniente.

Dislclaimer: Eu sou o autor desta biblioteca

.

Uma coisa importante a fazer é testar independentemente sua lógica de negócio

Eu certamente não assumir que a pessoa que escreveu o código JAX-RS e está olhando para teste de unidade a interface é de alguma forma, por algum motivo bizarro, inexplicável, alheia à noção de que ele ou ela pode unidade testar outras partes do o programa, incluindo aulas de lógica de negócios. É quase útil para afirmar o óbvio e observou-se repetidamente que as respostas precisam ser testados, também.

Ambos Jersey e RESTEasy ter aplicações cliente e no caso de RESTEasy você pode usar as mesmas annoations (mesmo fator fora de interface anotada e uso no lado do cliente e servidor de seus testes).

RESTO não o que este serviço pode fazer por você; RESTO o que você pode fazer por este serviço.

Mantenha-o simples. Ter um olhar para https://github.com/valid4j/http-matchers que pode ser importado de Maven Central.

    <dependency>
        <groupId>org.valid4j</groupId>
        <artifactId>http-matchers</artifactId>
        <version>1.0</version>
    </dependency>

Exemplo de uso:

// Statically import the library entry point:
import static org.valid4j.matchers.http.HttpResponseMatchers.*;

// Invoke your web service using plain JAX-RS. E.g:
Client client = ClientBuilder.newClient();
Response response = client.target("http://example.org/hello").request("text/plain").get();

// Verify the response
assertThat(response, hasStatus(Status.OK));
assertThat(response, hasHeader("Content-Encoding", equalTo("gzip")));
assertThat(response, hasEntity(equalTo("content")));
// etc...

Como eu entendo o principal objetivo do auther desta questão é dissociar JAX RS camada de um negócio. E teste de unidade apenas o primeiro. Dois problemas básicos aqui temos de resolver:

  1. Executar no teste de algum servidor web / aplicação, colocar componentes RS JAX em isto. E somente eles.
  2. Serviços de negócios Mock dentro JAX RS componentes / camada REST.

O primeiro é resolvido com Arquillian. O segundo está perfeitamente descrito no arquillican e simulada

Aqui está um exemplo do código, que podem ser diferentes se você usar outro servidor de aplicativos, mas eu espero que você começa a idéia básica e vantagens.

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.brandmaker.skinning.service.SomeBean;

/**
* Created by alexandr on 31.07.15.
*/
@Path("/entities")
public class RestBean
{
   @Inject
   SomeBean bean;

   @GET
   public String getEntiry()
   {
       return bean.methodToBeMoked();
   }
}

import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import com.google.common.collect.Sets;

/**
*/
@ApplicationPath("res")
public class JAXRSConfiguration extends Application
{
   @Override
   public Set<Class<?>> getClasses()
   {
       return Sets.newHashSet(RestBean.class);
   }
}


public class SomeBean
{
   public String methodToBeMoked()
   {
       return "Original";
   }
}

import javax.enterprise.inject.Specializes;

import com.brandmaker.skinning.service.SomeBean;

/**
*/
@Specializes
public class SomeBeanMock extends SomeBean
{
   @Override
   public String methodToBeMoked()
   {
       return "Mocked";
   }
}

@RunWith(Arquillian.class)
public class RestBeanTest
{
   @Deployment
   public static WebArchive createDeployment() {
       WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
               .addClasses(JAXRSConfiguration.class, RestBean.class, SomeBean.class, SomeBeanMock.class)
               .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
       System.out.println(war.toString(true));
       return war;
   }

   @Test
   public void should_create_greeting() {
       Client client = ClientBuilder.newClient();
       WebTarget target = client.target("http://127.0.0.1:8181/test/res/entities");
       //Building the request i.e a GET request to the RESTful Webservice defined
       //by the URI in the WebTarget instance.
       Invocation invocation = target.request().buildGet();
       //Invoking the request to the RESTful API and capturing the Response.
       Response response = invocation.invoke();
       //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
       //into the instance of Books by using JAXB.
       Assert.assertEquals("Mocked", response.readEntity(String.class));
   }
}

Um par de notas:

  1. JAX RS configuração sem web.xml é usado aqui.
  2. JAX RS Cliente é usado aqui (sem RESTEasy / Jersey, eles expõem API mais conveniente)
  3. Quando começa teste, corredor de Arquillian começa a trabalhar. Aqui você pode encontrar a forma de testes do configure para Arquillian com servidor de aplicação necessária.
  4. Dependendo do servidor de aplicação escolhida, uma url na teste será diferente um pouco. Outra porta pode ser usada. 8181 é usado por Glassfish incorporado no meu exemplo.

Hope, ele vai ajudar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top