JAX-RS Webサービスをテストしますか?


84

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

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

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

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


6
良い質問ですが、HTTPを介してテストしている場合、これは統合テストであると私は思います。
トムダッカリング2011年

トム。あなたは、絶対に正しい。このために、ダミーのHTTPエミュレーター/軽量コンテナーを挿入する必要があります。node.jsでは、世界のスーパーテストがこれを行います。express.jsをエミュレートできます。
FıratKÜÇÜK

回答:


34

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


6
re:now bad link基本的に、ジャージのコンシューマーを使用してWebリソースを消費することにより、ユニットテストを示すジャージ/サンプルに記載されている例を見つけることができます。 download.java.net/maven/2/com/sun/jersey/samples/bookstore/...
rogerdpack

2
このプロジェクトはGitHubにあり、src / testフォルダーでテストを見つけます:github.com/jersey/jersey/tree/master/examples/bookstore-webapp
Venkat

2
私はこの答えを疑うことはありませんが、Jerseyが常にJAX-RS会話に参加するのは非常に面白いと思います。場合によっては(WebSphere、残念ながら正確には)、それが利用できず、すべての受け入れ可能な回答の99%がレンダリングされます。 StackOverflowでnullおよびvoid。

26

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


1
ライブラリが良さそうだったので、私はあなたの投稿に投票しましたが、彼らは確かに多くの依存するjarファイルを使用しています...
Perry Tew 2012

17

ジェームズが言ったように; Jerseyには組み込みのテストフレームワークがあります。簡単なHelloWorldの例は次のようになります。

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-hk2java.lang.IllegalStateException: InjectionManagerFactorynot foundエラーが発生したため、依存関係として追加する必要がありました(この質問を参照)。それ以外の場合、この例はうまく機能します。
サラN

7

あなたはおそらくあなたのビジネスロジックを実装するいくつかのJavaコードを書き、それからあなたはそれのためのウェブサービスエンドポイントを生成しました。

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

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

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


2
あなたはまったく正しいですが、返される実際のHTTP応答、特にHTTPステータスコードもテストする必要があります。
Einar

6

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


コールハンドラをモックする方法の良い例はありますか?JerseyHttpCall-> MyResource-> CallHandler.getSomething()ここでCallHandlerをモックするにはどうすればよいですか?
Balaji Boggaram Ramanarayan 2014

3

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


3

AlchemyRESTクライアントジェネレーターを見てください。これにより、舞台裏でジャージクライアントを使用してJAX-RSWebサービスクラスのプロキシ実装を生成できます。事実上、単体テストから単純なJavaメソッドとしてWebサービスメソッドを呼び出します。http認証も処理します。

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

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


2

複雑にしないでおく。見ていhttps://github.com/valid4j/http-matchers Mavenの中央からインポートすることができます。

    <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ıratKÜÇÜK

私のアプリケーションでは、ModelMapperを使用して、「DTO」クラスから「ビジネスオブジェクト」クラスに「マッピング」します。これらのクラスは、基盤となる「サービス」クラスによって理解されます。これは、個別にテストするのに適した例です。
jkerak 2016年

また、現在の場合のように、RESTアプレットの複雑さがほとんどないため、モックがアプリケーション層よりも大きくなることがあります。:)
tekHedd

1

私が理解しているように、この問題の認証者の主な目的は、JAXRSレイヤーをビジネスレイヤーから切り離すことです。そして、最初のものだけをユニットテストします。ここで解決しなければならない2つの基本的な問題:

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

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

願わくば、それが役立つでしょう。


このタイプのものは、組み込みのジャージテストフレームワークによってサポートされていますか?すでにJerseyで利用できるものがある場合は、「さらに別のフレームワーク」とそのすべてのjarファイルをプロジェクトに追加することをためらっています。
jkerak 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.