Bir JAX-RS Web Hizmetini mi test ediyorsunuz?


84

Şu anda JAX-RS (RESTful Web Hizmetleri için Java API) tabanlı web hizmeti için otomatik testler oluşturmanın yollarını arıyorum .

Temel olarak ona belirli girdileri göndermek ve beklenen yanıtları aldığımı doğrulamak için bir yola ihtiyacım var. Bunu JUnit aracılığıyla yapmayı tercih ederim, ancak bunun nasıl başarılacağından emin değilim.

Web hizmetlerinizi test etmek için hangi yaklaşımı kullanıyorsunuz?

Güncelleme: Entzik'in işaret ettiği gibi, web hizmetini iş mantığından ayırmak, iş mantığını birim test etmeme izin veriyor. Bununla birlikte, doğru HTTP durum kodlarını vb. Test etmek istiyorum.


6
Güzel soru - ancak şunu söyleyebilirim ki, HTTP üzerinden test ediyorsanız, bunun entegrasyon testi olduğu bana çarpıyor.
Tom Duckering

Tom. Kesinlikle haklısın. Bunun için sahte bir HTTP emülatörü / hafif bir konteyner enjekte etmeliyiz. Node.js'de dünya süper testi bunu yapar. Express.js'yi taklit edebilirsiniz.
Fırat KÜÇÜK

Yanıtlar:


34

Jersey , birim testleri yazmayı gerçekten kolaylaştıran harika bir RESTful istemci API'si ile birlikte gelir. Jersey ile birlikte gelen örneklerdeki birim testlerine bakın. Bu yaklaşımı, Apache Camel'de REST desteğini test etmek için kullanıyoruz , ilgileniyorsanız test durumları burada.


6
re: now bad link Temel olarak web kaynaklarını tüketmek için Jersey'in tüketicilerini kullanarak birim testlerini gösteren formada / numunelerde belirtilen örnekleri bulabilirsiniz. download.java.net/maven/2/com/sun/jersey/samples/bookstore/…
rogerdpack

2
Bu proje GitHub'da, src / test klasöründe testleri bulun: github.com/jersey/jersey/tree/master/examples/bookstore-webapp
Venkat

2
Bu yanıttan şüphem yok, ancak Jersey'nin her zaman bir JAX-RS görüşmesine girmesini inanılmaz derecede komik buluyorum, bazı durumlarda (ne yazık ki WebSphere) mevcut olmadığında ve tüm kabul edilebilir yanıtların% 99'unu oluşturuyor. Stack Overflow null ve void.

26

REST Assured'i deneyebilirsiniz, bu da REST servislerini test etmeyi ve Java'da (JUnit veya TestNG kullanarak) yanıtı doğrulamayı çok kolaylaştırır.


1
Gönderinize oy verdim çünkü kütüphane iyi görünüyordu, ama kesinlikle çok sayıda bağımlı kavanoz kullanıyorlar ...
Perry Tew

18

James'in dediği gibi; Jersey için yerleşik test çerçevesi vardır . Basit bir merhaba dünya örneği şöyle olabilir:

maven entegrasyonu için pom.xml. Koştuğun zaman mvn test. Çerçeveler bir boz kap başlatır. Bağımlılıkları değiştirerek iskele veya tomcat kullanabilirsiniz.

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

Bu örnek uygulamayı kontrol edebilirsiniz .


Jersey 2.29.1 ile, jersey-hk2bir bağımlılık olarak eklemek zorunda kaldım çünkü java.lang.IllegalStateException: InjectionManagerFactorybulunamadı hatası alıyordum ( Bu soruya bakın ). Aksi takdirde bu örnek iyi sonuç verir.
Sarah N

7

Muhtemelen iş mantığınızı uygulayan bir java kodu yazdınız ve ardından bunun için web hizmetleri uç noktasını oluşturdunuz.

Yapılması gereken önemli bir şey, iş mantığınızı bağımsız olarak test etmektir. Saf java kodu olduğu için bunu normal JUnit testleri ile yapabilirsiniz.

Şimdi, web hizmetleri kısmı sadece bir bitiş noktası olduğundan emin olmak istediğiniz şey, oluşturulan sıhhi tesisatın (stub'lar, vb.) Java kodunuzla senkronize olduğundan emin olmaktır. bunu, oluşturulan web hizmeti java istemcilerini çağıran JUnit testleri yazarak yapabilirsiniz. Bu, web hizmetleri öğelerini güncellemeden java imzalarınızı değiştirdiğinizde size haber verecektir.

Web hizmetleri tesisatınız her derlemede derleme sisteminiz tarafından otomatik olarak oluşturulursa, uç noktaları test etmek gerekmeyebilir (tümünün doğru şekilde oluşturulduğu varsayılarak). Paranoya seviyenize bağlıdır.


2
Oldukça haklısınız, yine de döndürülen gerçek HTTP yanıtlarını, özellikle HTTP durum kodlarını test etmem gerekiyor.
Einar

6

Soruyu yayınlama tarihinden itibaren çok geç olsa da, bunun benzer bir sorusu olan diğerleri için faydalı olabileceğini düşündüm. Jersey , yanıt durum kodları dahil RESTful Web Hizmetinizi test etmenize olanak tanıyan Jersey Test Framework adlı bir test çerçevesiyle birlikte gelir . Testlerinizi Grizzly, HTTPServer ve / veya EmbeddedGlassFish gibi hafif konteynerlerde çalıştırmak için kullanabilirsiniz. Ayrıca çerçeve, testlerinizi GlassFish veya Tomcat gibi normal bir web kapsayıcısında çalıştırmak için kullanılabilir.


Çağrı işleyicileriyle nasıl alay edileceğine dair iyi bir örnek var mı? JerseyHttpCall -> MyResource -> CallHandler.getSomething () CallHandler ile nasıl alay edebiliriz burada?
Balaji Boggaram Ramanarayan

3

Restful Services'ı aramak için Apache'nin HTTPClient'ini (http://hc.apache.org/) kullanıyorum. HTTP İstemci kitaplığı alma, gönderme veya ihtiyacınız olan diğer işlemleri kolayca gerçekleştirmenize olanak tanır. Hizmetiniz xml bağlama için JAXB kullanıyorsa, HTTP isteğinden gelen girdileri ve çıktıları serileştirmek ve seri durumdan çıkarmak için bir JAXBContext oluşturabilirsiniz.


3

Alchemy rest istemci jeneratörüne bir göz atın . Bu, sahnenin arkasında Jersey istemcisini kullanarak JAX-RS web hizmeti sınıfınız için bir proxy uygulaması oluşturabilir. Etkili bir şekilde, birim testlerinizden basit java yöntemleri olarak size web hizmeti yöntemlerini çağıracaksınız. Http kimlik doğrulamasını da işler.

Kolaylık sağlamak için testleri basitçe çalıştırmanız gerekiyorsa, kod üretimi yoktur.

Dislclaimer: Ben bu kütüphanenin yazarıyım.


2

Basit tutun. Maven Central'dan içe aktarılabilen https://github.com/valid4j/http-matchers'a bir göz atın .

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

Kullanım örneği:

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

1

Yapılması gereken önemli bir şey, iş mantığınızı bağımsız olarak test etmektir.

Kesinlikle, JAX-RS kodunu yazan ve arayüzü birim test etmek isteyen kişinin, tuhaf, açıklanamaz bir nedenden ötürü, programın diğer bölümlerini test edebileceği fikrinden habersiz olduğunu kesinlikle varsaymam. iş mantığı sınıfları dahil. Açık olanı belirtmek pek yardımcı olmaz ve yanıtların da test edilmesi gerektiği defalarca vurgulanmıştır.

Hem Jersey hem de RESTEasy istemci uygulamalarına sahiptir ve RESTEasy söz konusu olduğunda aynı açıklamaları kullanabilirsiniz (hatta açıklamalı arayüzü hesaba katmayın ve testlerinizin istemci ve sunucu tarafında kullanın).

DİNLENİN bu hizmet sizin için neler yapabilir; Bu hizmet için yapabileceklerinizi DİNLENİN.


İnsanlar bazı kesişen endişeleri test etmek isteyebilir. Örneğin doğrulama, kimlik doğrulama, istenen HTTP başlıkları vb. Böylece insanlar JAX-RS kodlarını test etmeyi tercih edebilir.
Fırat KÜÇÜK

Uygulamamda, ModelMapper'ı "DTO" sınıflarından, temeldeki "hizmet" sınıfları tarafından anlaşılan "iş nesnesi" sınıflarına "eşlemek" için kullanıyorum. Bu, bağımsız olarak test etmenin iyi olacağı bir şeye örnektir.
jkerak

Ve bazen REST uygulaması o kadar az karmaşıklığa sahiptir ki, benim durumumda olduğu gibi, taklitler uygulama katmanından daha büyük olur. :)
tekHedd

1

Anladığım kadarıyla bu sorunun ana amacı, JAX RS katmanını iş dünyasından ayırmaktır. Ve sadece ilkini test edin. Burada çözmemiz gereken iki temel sorun:

  1. Bazı web / uygulama sunucularını test edin, içine JAX RS bileşenleri koyun. Ve sadece onlar.
  2. JAX RS bileşenleri / REST katmanı içindeki sahte iş hizmetleri.

İlki Arquillian ile çözüldü. İkincisi, arquillican ve sahte olarak mükemmel bir şekilde tanımlanmıştır.

İşte kodun bir örneği, başka bir uygulama sunucusu kullanıyorsanız farklı olabilir, ancak umarım temel fikir ve avantajları elde edersiniz.

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

Birkaç not:

  1. Web.xml içermeyen JAX RS yapılandırması burada kullanılır.
  2. JAX RS İstemcisi burada kullanılır (RESTEasy / Jersey yok, daha uygun API ortaya çıkarırlar)
  3. Test başladığında, Arquillian'ın koşucusu çalışmaya başlar. Buraya , gerekli uygulama sunucusuyla Arquillian için testlerin nasıl yapılandırılacağını bulabilirsiniz.
  4. Seçilen uygulama sunucusuna bağlı olarak, testteki bir url biraz farklı olacaktır. Başka bir bağlantı noktası kullanılabilir. 8181, benim örneğimde Glassfish Embedded tarafından kullanılmaktadır.

Umarım yardımcı olur.


bu tür şeyler yerleşik jarse test çerçevesi tarafından destekleniyor mu? Jersey'de halihazırda mevcut bir şeyim varsa, "başka bir çerçeve" yi ve tüm kavanozlarını projeme eklemekte tereddüt ediyorum.
jkerak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.