Obecnie szukam sposobów tworzenia automatycznych testów dla usługi internetowej opartej na JAX-RS (Java API for RESTful Web Services).
Zasadniczo potrzebuję sposobu, aby przesłać mu określone dane wejściowe i sprawdzić, czy otrzymuję oczekiwane odpowiedzi. Wolałbym to zrobić za pośrednictwem JUnit, ale nie jestem pewien, jak można to osiągnąć.
Jakiego podejścia używasz do testowania swoich usług internetowych?
Aktualizacja: Jak zauważył entzik, oddzielenie usługi sieciowej od logiki biznesowej pozwala mi na testowanie jednostkowe logiki biznesowej. Jednak chcę również przetestować prawidłowe kody stanu HTTP itp.
Odpowiedzi:
Jersey jest wyposażony w świetne API klienta RESTful, które sprawia, że pisanie testów jednostkowych jest naprawdę łatwe. Zobacz testy jednostkowe w przykładach dostarczanych z Jersey. Używamy tego podejścia do testowania obsługi REST w Apache Camel , jeśli jesteś zainteresowany, przypadki testowe są tutaj
źródło
Możesz wypróbować REST Assured, który bardzo ułatwia testowanie usług REST i sprawdzanie poprawności odpowiedzi w Javie (za pomocą JUnit lub TestNG).
źródło
Jak powiedział James; Jest wbudowany framework testowy dla Jersey. Prosty przykład Hello World może wyglądać tak:
pom.xml do integracji maven. Kiedy biegasz
mvn test
. Struktury rozpoczynają kontener grizzly. Możesz użyć jetty lub tomcat poprzez zmianę zależności.... <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); } }
Możesz sprawdzić tę przykładową aplikację.
źródło
jersey-hk2
jako zależność, ponieważ otrzymywałemjava.lang.IllegalStateException: InjectionManagerFactory
błąd „nie znaleziono” (zobacz to pytanie ). W przeciwnym razie ten przykład działa dobrze.Prawdopodobnie napisałeś kod java, który implementuje logikę biznesową, a następnie wygenerowałeś dla niego punkt końcowy usług internetowych.
Ważną rzeczą do zrobienia jest niezależne przetestowanie logiki biznesowej. Ponieważ jest to czysty kod java, możesz to zrobić za pomocą regularnych testów JUnit.
Teraz, ponieważ część usług sieci Web jest tylko punktem końcowym, chcesz się upewnić, że wygenerowana instalacja hydrauliczna (odgałęzienia itp.) Jest zsynchronizowana z kodem Java. możesz to zrobić, pisząc testy JUnit, które wywołują wygenerowane klienty Java usługi WWW. Dzięki temu będziesz wiedzieć, kiedy zmienisz swoje podpisy java bez aktualizowania usług internetowych.
Jeśli instalacja hydrauliczna usług internetowych jest automatycznie generowana przez system kompilacji przy każdej kompilacji, może nie być konieczne testowanie punktów końcowych (zakładając, że wszystko jest poprawnie wygenerowane). Zależy od poziomu paranoi.
źródło
Chociaż jest za późno od daty wysłania pytania, pomyślałem, że może to być przydatne dla innych, którzy mają podobne pytanie. Jersey jest dostarczany z platformą testową zwaną Jersey Test Framework, która umożliwia testowanie usługi internetowej RESTful, w tym kodów stanu odpowiedzi. Możesz go użyć do uruchomienia testów na lekkich kontenerach, takich jak Grizzly, HTTPServer i / lub EmbeddedGlassFish. Framework może być również używany do uruchamiania testów w zwykłym kontenerze WWW, takim jak GlassFish lub Tomcat.
źródło
Używam HTTPClient Apache (http://hc.apache.org/) do wywoływania Restful Services. Biblioteka klienta HTTP umożliwia łatwe wykonywanie operacji pobierania, wysyłania lub innych potrzebnych operacji. Jeśli usługa używa JAXB do powiązania XML, możesz utworzyć JAXBContext w celu serializacji i deserializacji danych wejściowych i wyjściowych z żądania HTTP.
źródło
Spójrz na generator klienta reszty Alchemy . Może to wygenerować implementację proxy dla Twojej klasy usług sieciowych JAX-RS przy użyciu klienta koszulki za kulisami. Skutecznie będziesz wywoływać metody usługi sieciowej jako proste metody java z testów jednostkowych. Obsługuje również uwierzytelnianie HTTP.
Nie ma potrzeby generowania kodu, jeśli chcesz po prostu uruchomić testy, więc jest to wygodne.
Zastrzeżenie: jestem autorem tej biblioteki.
źródło
Nie komplikuj. Spójrz na https://github.com/valid4j/http-matchers, które można zaimportować z Maven Central.
<dependency> <groupId>org.valid4j</groupId> <artifactId>http-matchers</artifactId> <version>1.0</version> </dependency>
Przykład użycia:
// 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...
źródło
Z pewnością nie zakładałbym, że osoba, która napisała kod JAX-RS i chce przeprowadzić testy jednostkowe interfejsu, jest w jakiś sposób, z jakiegoś dziwnego, niewytłumaczalnego powodu, obojętna na to, że może jednostkowo testować inne części programu, w tym klasy logiki biznesowej. Stwierdzenie tego, co oczywiste, nie jest pomocne, a wielokrotnie wskazywano, że odpowiedzi również należy przetestować.
Zarówno Jersey, jak i RESTEasy mają aplikacje klienckie, aw przypadku RESTEasy możesz użyć tych samych adnotacji (nawet uwzględnij interfejs z adnotacjami i użyj po stronie klienta i serwera w testach).
REST nie tego, co ta usługa może zrobić dla Ciebie; POCZUJ, co możesz zrobić dla tej usługi.
źródło
Jak rozumiem, głównym celem autora tego wydania jest oddzielenie warstwy JAX RS od biznesowej. Test jednostkowy tylko pierwszy. Tutaj musimy rozwiązać dwa podstawowe problemy:
Pierwszą rozwiązuje Arquillian. Drugi jest doskonale opisany w arquillican i mock
Oto przykład kodu, może się różnić, jeśli używasz innego serwera aplikacji, ale mam nadzieję, że uzyskasz podstawowy pomysł i zalety.
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)); } }
Kilka uwag:
Mam nadzieję, że to pomoże.
źródło