Atualmente, estou procurando maneiras de criar testes automatizados para um serviço da Web baseado em JAX-RS (Java API para RESTful Web Services).
Basicamente, preciso enviar certas entradas e verificar se obtenho as respostas esperadas. Eu prefiro fazer isso por meio do JUnit, mas não tenho certeza de como isso pode ser feito.
Que abordagem você usa para testar seus serviços da web?
Atualização: como entzik apontou, separar o serviço da web da lógica de negócios me permite testar a lógica de negócios de unidade. No entanto, também quero testar os códigos de status HTTP corretos, etc.
java
web-services
unit-testing
junit
jax-rs
Einar
fonte
fonte
Respostas:
Jersey vem com uma excelente API de cliente RESTful que torna a escrita de testes de unidade realmente fácil. Consulte os testes de unidade nos exemplos fornecidos com o Jersey. Usamos essa abordagem para testar o suporte REST no Apache Camel , se você estiver interessado, os casos de teste estão aqui
fonte
Você pode experimentar REST Assured, que torna muito simples testar serviços REST e validar a resposta em Java (usando JUnit ou TestNG).
fonte
Como James disse; Há uma estrutura de teste integrada para Jersey. Um exemplo simples de hello world pode ser assim:
pom.xml para integração maven. Quando você corre
mvn test
. Frameworks iniciam um contêiner grizzly. Você pode usar jetty ou tomcat alterando 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 amostra.
fonte
jersey-hk2
como uma dependência porque estava recebendo umjava.lang.IllegalStateException: InjectionManagerFactory
erro não encontrado (veja esta pergunta ). Caso contrário, este exemplo funciona bem.Você provavelmente escreveu algum código java que implementa sua lógica de negócios e, em seguida, gerou o ponto de extremidade de serviços da web para ele.
Uma coisa importante a fazer é testar independentemente sua lógica de negócios. Como é código Java puro, você pode fazer isso com testes JUnit regulares.
Agora, como a parte dos serviços da web é apenas um ponto final, o que você deseja ter certeza é que o encanamento gerado (stubs, etc) está em sincronia com seu código java. você pode fazer isso escrevendo testes JUnit que invocam os clientes java de serviço da web gerados. Isso permitirá que você saiba quando alterar suas assinaturas java sem atualizar o material de serviços da web.
Se o encanamento de seus serviços da web for gerado automaticamente por seu sistema de compilação a cada compilação, pode não ser necessário testar os terminais (presumindo que tudo seja gerado corretamente). Depende do seu nível de paranóia.
fonte
Embora seja muito tarde para a data de postagem da pergunta, pensei que isso possa ser útil para outras pessoas que tenham uma pergunta semelhante. Jersey vem com uma estrutura de teste chamada Jersey Test Framework, que permite testar seu serviço da Web RESTful, incluindo os códigos de status de resposta. Você pode usá-lo para executar seus testes em contêineres leves como Grizzly, HTTPServer e / ou EmbeddedGlassFish. Além disso, a estrutura pode ser usada para executar seus testes em um contêiner da web regular, como GlassFish ou Tomcat.
fonte
Eu uso o HTTPClient do Apache (http://hc.apache.org/) para chamar o Restful Services. A biblioteca do cliente HTTP permite que você execute facilmente get, post ou qualquer outra operação necessária. Se o seu serviço usa JAXB para ligação xml, você pode criar um JAXBContext para serializar e desserializar entradas e saídas da solicitação HTTP.
fonte
Dê uma olhada no gerador de cliente de descanso Alchemy . Isso pode gerar uma implementação de proxy para sua classe de serviço da web JAX-RS usando o cliente jersey nos bastidores. Efetivamente, você chamará métodos de serviço da web como métodos java simples de seus testes de unidade. Lida com autenticação http também.
Não há geração de código envolvida se você precisar simplesmente executar testes para que seja conveniente.
Isenção de responsabilidade: eu sou o autor desta biblioteca.
fonte
Mantenha simples. Dê uma olhada em https://github.com/valid4j/http-matchers que pode ser importado do 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...
fonte
Eu certamente não presumiria que a pessoa que escreveu o código JAX-RS e está procurando fazer o teste de unidade da interface esteja de alguma forma, por algum motivo bizarro e inexplicável, alheio à noção de que ele ou ela pode testar a unidade de outras partes do programa, incluindo classes de lógica de negócios. Não ajuda muito afirmar o óbvio, e foi dito repetidamente que as respostas também precisam ser testadas.
Tanto Jersey quanto RESTEasy têm aplicativos clientes e, no caso do RESTEasy, você pode usar as mesmas anotações (até mesmo fatorar a interface anotada e usar no cliente e no servidor de seus testes).
DESCANSE não o que este serviço pode fazer por você; DESCANSE o que você pode fazer por este serviço.
fonte
Pelo que entendi, o principal objetivo do autor desta edição é desacoplar a camada JAX RS do negócio. E teste de unidade apenas o primeiro. Temos que resolver dois problemas básicos aqui:
O primeiro é resolvido com Arquillian. O segundo é perfeitamente descrito em arquillican e mock
Aqui está um exemplo do código. Ele pode ser diferente se você usar outro servidor de aplicativos, mas espero que você tenha uma ideia 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)); } }
Algumas notas:
Espero que ajude.
fonte