web-dev-qa-db-ja.com

JAX-RS Webサービスの単体テスト?

現在、 JAX-RS (RESTful WebサービスのJava API)ベースのWebサービスの自動テストを作成する方法を探しています。

基本的に、特定の入力を送信し、期待される応答が得られることを確認する方法が必要です。私はJUnitを介してこれを行うことを望んでいますが、それがどのように達成できるかわかりません。

Webサービスをテストするためにどのようなアプローチを使用していますか?

更新:entzikが指摘したように、Webサービスをビジネスロジックから切り離すことで、ビジネスロジックの単体テストを行うことができます。ただし、正しいHTTPステータスコードなどについてもテストしたいと思います。

78
Einar

Jersey には、ユニットテストの作成を非常に簡単にする優れたRESTfulクライアントAPIが付属しています。 Jerseyに同梱されている例の単体テストを参照してください。このアプローチを使用して、RESTの Apache Camel のサポートをテストします。興味がある場合は テストケースはこちら

35
James Strachan

REST Assured を試すことができます非常に RESTサービスをテストし、Javaで応答を検証するのは簡単です(JUnitまたはTestNGを使用)。

24
Johan

ジェームズが言ったように。組み込みの テストフレームワーク 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);
    }
}

this サンプルアプリケーションを確認できます。

12
Fırat KÜÇÜK

おそらく、ビジネスロジックを実装するコードをいくつかJavaで記述し、そのためのWebサービスエンドポイントを生成しました。

重要なことは、ビジネスロジックを個別にテストすることです。純粋なJavaコードなので、通常のJUnitテストでそれを行うことができます。

これで、Webサービスパーツはエンドポイントに過ぎないため、生成する配管(スタブなど)がJavaコードと同期していることを確認する必要があります。生成されたWebサービスJavaクライアントを呼び出すJUnitテストを作成します。これにより、Webサービスを更新せずにJava署名を変更したときに通知されます。

Webサービスの配管がビルドごとにビルドシステムによって自動的に生成される場合、エンドポイントをテストする必要はありません(すべて適切に生成されていると仮定)。妄想のレベルに依存します。

6
entzik

質問を投稿した日付からは遅すぎますが、これは同様の質問を持っている他の人にとって有用かもしれないと考えました。 Jerseyには、応答ステータスコードなど、RESTful Webサービスをテストできる Jersey Test Framework というテストフレームワークが付属しています。これを使用して、Grizzly、HTTPServer、EmbeddedGlassFishなどの軽量コンテナでテストを実行できます。また、フレームワークを使用して、GlassFishやTomcatなどの通常のWebコンテナでテストを実行できます。

6
Naresh

Alchemy rest client generator をご覧ください。これにより、ジャージークライアントを舞台裏で使用して、JAX-RS Webサービスクラスのプロキシ実装を生成できます。事実上、単純なJava単体テストからのメソッド。HTTP認証も処理します。

簡単にテストを実行する必要がある場合、コード生成は関係ないので便利です。

免責事項:私はこのライブラリの著者です。

3
Ashish Shinde

Apacheの HTTPClient(http://hc.Apache.org/) を使用してRestful Servicesを呼び出します。 HTTPクライアントライブラリを使用すると、get、post、またはその他の必要な操作を簡単に実行できます。サービスがxmlバインディングにJAXBを使用している場合、JAXBContextを作成して、HTTP要求からの入力と出力をシリアル化および非シリアル化できます。

3
Chris Dail

複雑にしないでおく。 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...
2
keyoxy

重要なことは、ビジネスロジックを個別にテストすることです

JAX-RSコードを書いてインターフェースの単体テストをしようとしている人が、何らかの奇妙な、不可解な理由で、プログラムの他の部分を単体テストできるという概念を忘れているとは、決して思いません。ビジネスロジッククラスを含む。明白なことを述べることはほとんど役に立たず、応答もテストする必要があるという点が繰り返し述べられました。

JerseyとRESTEasyの両方にクライアントアプリケーションがあり、RESTEasyの場合は同じ注釈を使用できます(注釈付きインターフェースを除外し、テストのクライアント側とサーバー側で使用することもできます)。

このサービスでできることはRESTではありません。 RESTこのサービスでできること。

2
rickoshay

私が理解しているように、この問題の作成者の主な目的は、JAX RSレイヤーをビジネスレイヤーから分離することです。そして、最初のものだけを単体テストします。ここで解決しなければならない2つの基本的な問題:

  1. いくつかのWeb /アプリケーションサーバーをテストして実行し、JAX RSコンポーネントをそのサーバーに配置します。そして彼らだけ。
  2. JAX RSコンポーネント/ RESTレイヤー内のビジネスサービスのモック。

最初のものはArquillianで解決されます。 2つ目は arquillican and 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 Clientが使用されます(RESTEasy/Jerseyは使用せず、より便利なAPIを公開します)
  3. テストが開始されると、Arquillianのランナーが動作を開始します。 こちら 必要なアプリケーションサーバーでArquillianのテストを構成する方法を見つけることができます。
  4. 選択したアプリケーションサーバーに応じて、テストのURLは少し異なります。別のポートが使用される場合があります。私の例では、Glassfish Embeddedが8181を使用しています。

希望、それが役立つだろう。

1
Alexandr