JAX-RS 웹 서비스 테스트?


84

현재 JAX-RS (RESTful 웹 서비스 용 Java API) 기반 웹 서비스에 대한 자동화 된 테스트를 만드는 방법을 찾고 있습니다 .

기본적으로 특정 입력을 보내고 예상 응답을 받는지 확인하는 방법이 필요합니다. JUnit을 통해이 작업을 수행하고 싶지만 어떻게 달성 할 수 있는지 잘 모르겠습니다.

웹 서비스를 테스트하기 위해 어떤 접근 방식을 사용합니까?

업데이트 : entzik이 지적했듯이 비즈니스 로직에서 웹 서비스를 분리하면 비즈니스 로직을 단위 테스트 할 수 있습니다. 그러나 올바른 HTTP 상태 코드 등을 테스트하고 싶습니다.


6
좋은 질문입니다. 그러나 HTTP를 통해 테스트하는 경우 이것이 통합 테스트라는 것을 알 수 있습니다.
— Tom Duckering 2011 년

톰. 당신은 절대적으로 옳다. 이를 위해 더미 HTTP 에뮬레이터 / 경량 컨테이너를 삽입해야합니다. node.js에서 world supertest는 이것을 만듭니다. express.js를 에뮬레이션 할 수 있습니다.
— Fırat KÜÇÜK

답변:


34

Jersey 는 단위 테스트 작성을 정말 쉽게 해주는 훌륭한 RESTful 클라이언트 API와 함께 제공됩니다. Jersey와 함께 제공되는 예제에서 단위 테스트를 참조하십시오. 이 접근 방식을 사용하여 Apache Camel 에서 REST 지원을 테스트합니다. 관심이있는 경우 테스트 사례는 여기에 있습니다.


6
re : now bad link 기본적으로 jersey의 소비자를 사용하여 웹 리소스를 사용함으로써 단위 테스트를 보여주는 jersey / samples에 언급 된 예제를 찾을 수 있습니다. download.java.net/maven/2/com/sun/jersey/samples/bookstore/…
— rogerdpack 2009

2
이 프로젝트는 GitHub에 있습니다. src / test 폴더에서 테스트를 찾으십시오. github.com/jersey/jersey/tree/master/examples/bookstore-webapp
— Venkat

2
나는이 대답을 의심하지 않는다. 그러나 Jersey가 항상 JAX-RS 대화에 들어가는 것이 엄청나게 웃기다. 어떤 경우에는 (불행히도 정확히 말하자면 WebSphere) 사용할 수없고 모든 수용 가능한 대답의 99 %를 렌더링한다. 스택 오버플로에서 null 및 void.

26

REST Assured 를 사용해 볼 수 있습니다. REST 서비스를 테스트하고 Java에서 응답을 검증하는 것이 매우 간단합니다 (JUnit 또는 TestNG 사용).


1
... 나는 도서관 보았다 좋은 원인 게시물을 선정,하지만 그들은 확실히 의존 항아리를 많이 사용
— 페리 튜에게

17

James가 말했듯이; 기본 제공 테스트 프레임 워크가 있습니다.Jersey에 대한 가 있습니다. 간단한 hello world 예제는 다음과 같습니다.

maven 통합을위한 pom.xml. 당신은 실행하면 mvn test. 프레임 워크는 그리즐리 컨테이너를 시작합니다. 종속성 변경을 통해 jetty 또는 tomcat을 사용할 수 있습니다.

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

이 샘플 애플리케이션을 확인할 수 있습니다 .


Jersey 2.29.1에서는 찾을 수 없음 오류가 발생 jersey-hk2했기 때문에 종속성 으로 추가해야했습니다 java.lang.IllegalStateException: InjectionManagerFactory( 이 질문 참조 ). 그렇지 않으면이 예제가 잘 작동합니다.
— Sarah N

7

비즈니스 로직을 구현하는 자바 코드를 작성한 다음이를위한 웹 서비스 엔드 포인트를 생성했을 것입니다.

중요한 것은 비즈니스 로직을 독립적으로 테스트하는 것입니다. 순수한 자바 코드이기 때문에 일반 JUnit 테스트로 할 수 있습니다.

이제 웹 서비스 부분은 끝 점일 뿐이므로 생성 된 배관 (스텁 등)이 Java 코드와 동기화되어 있는지 확인해야합니다. 생성 된 웹 서비스 자바 클라이언트를 호출하는 JUnit 테스트를 작성하면됩니다. 이것은 웹 서비스 항목을 업데이트하지 않고 Java 서명을 변경할 때 알려줍니다.

웹 서비스 배관이 모든 빌드에서 빌드 시스템에 의해 자동으로 생성되는 경우 엔드 포인트를 테스트 할 필요가 없습니다 (모두 올바르게 생성되었다고 가정). 편집증 수준에 따라 다릅니다.


2
반환되는 실제 HTTP 응답, 특히 HTTP 상태 코드도 테스트해야하지만 당신 말이 맞습니다.
— Einar

6

질문을 게시 한 날짜로부터 너무 늦었지만 비슷한 질문을 가진 다른 사람들에게 유용 할 것이라고 생각했습니다. Jersey에는 응답 상태 코드를 포함하여 RESTful 웹 서비스를 테스트 할 수 있는 Jersey Test Framework 라는 테스트 프레임 워크가 제공됩니다 . 이를 사용하여 Grizzly, HTTPServer 및 / 또는 EmbeddedGlassFish와 같은 경량 컨테이너에서 테스트를 실행할 수 있습니다. 또한 프레임 워크를 사용하여 GlassFish 또는 Tomcat과 같은 일반 웹 컨테이너에서 테스트를 실행할 수 있습니다.


호출 핸들러를 모의하는 방법에 대한 좋은 예가 있습니까? JerseyHttpCall-> MyResource-> CallHandler.getSomething () 여기서 CallHandler를 어떻게 모의 할 수 있습니까?
— Balaji Boggaram Ramanarayan 2014

3

Apache의 HTTPClient (http://hc.apache.org/) 를 사용하여 Restful Services를 호출합니다. HTTP 클라이언트 라이브러리를 사용하면 가져 오기, 게시 또는 필요한 기타 작업을 쉽게 수행 할 수 있습니다. 서비스에서 xml 바인딩에 JAXB를 사용하는 경우 JAXBContext를 만들어 HTTP 요청의 입력 및 출력을 직렬화 및 역 직렬화 할 수 있습니다.


3

Alchemy Rest 클라이언트 생성기 살펴보기 . 이렇게하면 뒤에서 저지 클라이언트를 사용하여 JAX-RS 웹 서비스 클래스에 대한 프록시 구현을 생성 할 수 있습니다. 효과적으로 단위 테스트에서 웹 서비스 메서드를 간단한 Java 메서드로 호출합니다. http 인증도 처리합니다.

간단하게 테스트를 실행해야하는 경우 코드 생성이 필요하지 않으므로 편리합니다.

면책 조항 : 나는이 라이브러리의 저자입니다.


2

단순하게 유지하십시오. Maven Central에서 가져올 수있는 https://github.com/valid4j/http-matchers 를 살펴보세요 .

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

사용 예 :

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

중요한 것은 비즈니스 로직을 독립적으로 테스트하는 것입니다.

JAX-RS 코드를 작성하고 인터페이스를 단위 테스트하려는 사람이 기이하고 설명 할 수없는 이유로 프로그램의 다른 부분을 단위 테스트 할 수 있다는 개념을 모르는 사람이라고 생각하지 않습니다. 비즈니스 로직 클래스를 포함합니다. 명백한 것을 언급하는 것은 거의 도움이되지 않으며 응답도 테스트 할 필요가 있다는 점이 반복적으로 제기되었습니다.

Jersey와 RESTEasy 모두 클라이언트 응용 프로그램이 있으며 RESTEasy의 경우 동일한 주석을 사용할 수 있습니다 (주석이있는 인터페이스를 제외하고 테스트의 클라이언트 및 서버 측에서 사용).

REST는이 서비스가 당신을 위해 할 수있는 일이 아닙니다. 이 서비스에 대해 수행 할 수있는 작업을 REST하십시오.


사람들은 교차 절단 문제를 테스트하고 싶을 수 있습니다. 예를 들어 유효성 검사, 인증, 원하는 HTTP 헤더 등이 있습니다. 따라서 사람들은 JAX-RS 코드 테스트를 선호 할 수 있습니다.
— Fırat KÜÇÜK

내 응용 프로그램에서 ModelMapper를 사용하여 "DTO"클래스에서 기본 "서비스"클래스에서 이해하는 "비즈니스 개체"클래스로 "매핑"합니다. 이것은 독립적으로 테스트하는 것이 좋은 예입니다.
— jkerak

그리고 때로는 REST 애플릿의 복잡성이 너무 적어서 현재의 경우와 같이 모의가 애플리케이션 계층보다 클 수 있습니다. :)
— tekHedd

1

이 문제의 인증 자의 주요 목적은 비즈니스 1에서 JAX RS 계층을 분리하는 것입니다. 그리고 첫 번째 만 단위 테스트합니다. 여기서 해결해야 할 두 가지 기본 문제 :

  1. 일부 웹 / 애플리케이션 서버를 테스트에서 실행하고 JAX RS 구성 요소를 그 안에 넣습니다. 그리고 그들 만.
  2. JAX RS 구성 요소 / REST 계층 내에서 비즈니스 서비스를 모의합니다.

첫 번째 문제는 Arquillian로 해결됩니다. 두 번째는 arquillican 및 mock으로

다음은 코드의 예입니다. 다른 애플리케이션 서버를 사용하면 다를 수 있지만 기본적인 아이디어와 이점을 얻으시기 바랍니다.

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

몇 가지 참고 사항 :

  1. web.xml이없는 JAX RS 구성이 여기에 사용됩니다.
  2. 여기에서는 JAX RS 클라이언트가 사용됩니다 (RESTEasy / Jersey가 없으며보다 편리한 API를 제공함).
  3. 테스트가 시작되면 Arquillian의 주자가 작동하기 시작합니다. 여기 에서 필요한 애플리케이션 서버로 Arquillian 테스트를 구성하는 방법을 찾을 수 있습니다.
  4. 선택한 응용 프로그램 서버에 따라 테스트의 URL이 약간 다릅니다. 다른 포트를 사용할 수 있습니다. 8181은 내 예제에서 Glassfish Embedded에서 사용됩니다.

희망, 도움이 될 것입니다.


내장 저지 테스트 프레임 워크에서 이러한 유형을 지원합니까? Jersey에서 이미 사용할 수있는 것이 있다면 "아직 다른 프레임 워크"와 모든 병을 프로젝트에 추가하는 것을 주저합니다.
— jkerak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.