Domanda

Attualmente sto cercando modi per creare test automatici per un JAX-RS (API Java per i servizi Web basati su RESTful Web Services).

Fondamentalmente ho bisogno di un modo per inviargli determinati input e verificare che ottenga le risposte attese. Preferirei farlo tramite JUnit, ma non sono sicuro di come farlo.

Quale approccio usi per testare i tuoi servizi web?

Aggiornamento: Come sottolineato da entzik, il disaccoppiamento del servizio Web dalla logica aziendale mi consente di testare l'unità della logica aziendale. Tuttavia, voglio anche verificare i codici di stato HTTP corretti, ecc.

È stato utile?

Soluzione

Jersey è dotato di un'eccellente API RESTful per i client che semplifica la scrittura di test di unità. Vedi i test unitari negli esempi forniti con Jersey. Utilizziamo questo approccio per testare il supporto REST in Apache Camel , se ti interessa casi di test sono qui

Altri suggerimenti

Puoi provare REST Assured che lo rende molto semplice da testare i servizi REST e convalidare la risposta in Java (usando JUnit o TestNG).

Come disse James; Esiste un framework di test incorporato per Jersey. Un semplice esempio di ciao mondo può essere così:

pom.xml per l'integrazione di Maven. Quando esegui mvn test . I frame iniziano un contenitore grigio. Puoi usare jetty o tomcat cambiando le dipendenze.

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

Puoi controllare questa applicazione di esempio.

Anche se è troppo tardi dalla data di pubblicazione della domanda, ho pensato che questo potrebbe essere utile per gli altri che hanno una domanda simile. Jersey viene fornito con un framework di test chiamato Jersey Test Framework che ti consente di testare il tuo RESTful Servizio Web, inclusi i codici di stato della risposta. Puoi usarlo per eseguire i test su contenitori leggeri come Grizzly, HTTPServer e / o EmbeddedGlassFish. Inoltre, è possibile utilizzare il framework per eseguire i test su un normale contenitore Web come GlassFish o Tomcat.

Probabilmente hai scritto del codice java che implementa la tua logica aziendale e quindi hai generato l'end point dei servizi web per questo.

Una cosa importante da fare è testare in modo indipendente la tua logica aziendale. Dal momento che è puro codice Java, puoi farlo con i test JUnit regolari.

Ora, poiché la parte dei servizi Web è solo un punto finale, quello che vuoi assicurarti è che l'impianto idraulico generato (stub, ecc.) sia sincronizzato con il tuo codice java. è possibile farlo scrivendo test JUnit che invocano i client java generati dal servizio Web. Questo ti farà sapere quando cambi le tue firme java senza aggiornare i servizi web.

Se l'impianto idraulico dei tuoi servizi web viene generato automaticamente dal tuo sistema di build in ogni build, potrebbe non essere necessario testare gli end point (supponendo che sia tutto correttamente generato). Dipende dal tuo livello di paranoia.

Uso HTTPClient di Apache (http://hc.apache.org/) per chiamare Servizi Restful . La libreria client HTTP consente di eseguire facilmente get, post o qualsiasi altra operazione necessaria. Se il tuo servizio utilizza JAXB per l'associazione xml, puoi creare un JAXBContext per serializzare e deserializzare input e output dalla richiesta HTTP.

Dai un'occhiata a Generatore client di riposo per alchimia . Questo può generare un'implementazione proxy per la tua classe di servizi web JAX-RS utilizzando il client jersey dietro le quinte. In effetti, ti chiamerai metodi di webservice come semplici metodi Java dai tuoi test unitari. Gestisce anche l'autenticazione http.

Non è richiesta la generazione di codice se è necessario semplicemente eseguire i test, quindi è conveniente.

Dichiarazione di non responsabilità: sono l'autore di questa libreria.

  
    

Una cosa importante da fare è testare in modo indipendente la tua logica aziendale

  

Certamente non presumo che la persona che ha scritto il codice JAX-RS e stia cercando di testare l'unità l'interfaccia sia in qualche modo, per qualche ragione bizzarra, inspiegabile, ignara dell'idea che lui o lei può unità testare altre parti di il programma, comprese le classi di business logic. Non è utile affermare l'ovvio e si è ripetutamente sottolineato che anche le risposte devono essere testate.

Sia Jersey che RESTEasy hanno applicazioni client e nel caso di RESTEasy è possibile utilizzare gli stessi fastidi (persino estrarre l'interfaccia annotata e utilizzarla sul lato client e server dei test).

REST non è ciò che questo servizio può fare per te; RESTA cosa puoi fare per questo servizio.

Semplificalo. Dai un'occhiata a https://github.com/valid4j/http-matchers che possono essere importati dalla centrale di Maven.

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

Esempio di utilizzo:

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

A quanto ho capito, lo scopo principale dell'auther di questo problema è di separare il livello JAX RS da quello aziendale. E unit test solo il primo. Due problemi di base qui dobbiamo risolvere:

  1. Esegui in prova alcuni server web / applicazioni, inserisci i componenti JAX RS esso. E solo loro.
  2. Servizi aziendali falsi all'interno di JAX RS componenti / livello REST.

Il primo è risolto con Arquillian. Il secondo è perfettamente descritto in arquillican and mock

Ecco un esempio del codice, potrebbe essere diverso se si utilizza un altro server delle applicazioni, ma spero che otterrai l'idea di base e i vantaggi.

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

Un paio di note:

  1. Qui viene utilizzata la configurazione JAX RS senza web.xml.
  2. Qui viene utilizzato il client JAX RS (no RESTEasy / Jersey, espongono API più convenienti)
  3. Quando inizia il test, il corridore di Arquillian inizia a lavorare. Qui puoi trovare come configurare i test per Arquillian con il server delle applicazioni necessario.
  4. A seconda del server delle applicazioni scelto, un URL in il test differirà leggermente. È possibile utilizzare un'altra porta. 8181 è usato da Glassfish Incorporato nel mio esempio.

Spero che sia d'aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top