2016-08-04 11 views
2

以下のテストケースを「クリーン」テスト、つまりテスト後にデータベースの変更を自動的にロールバックすることをお勧めします。「きれいな」統合テストの作成 - ジャージー2とスプリングを使用したREST

@Test 
public void testUpdate(){ 
    ClientConfig clientConfig = new ClientConfig(); 
    clientConfig.register(JacksonFeature.class); 
    Client client = ClientBuilder.newClient(clientConfig); 
    Name name = new Name(1L,"Updated","Updated"); 
    Response response = client 
      .target("http://localhost:8080/jersey-spring/name/").request().header("Content-type", MediaType.APPLICATION_JSON).post(Entity.json(name)); 
    Assert.assertTrue(response.getStatus() == 200); 
} 

残りのサービスは、統合テスト中にjetty-maven-pluginを使用して展開されます。私が今直面している問題は、 transactionalのテストを使用できないということです。これは、テスト後に手動でデータベースの状態を変更する必要があり、非常に面倒です。

私の質問は、jerseyをRESTプロバイダとして使用するときに、「クリーン」な統合テストを実行するための推奨されるアプローチです。私はJerseyTestも使ってみましたが、同じ問題に直面しています。

さまざまな理由から、JerseyをSpring MVCに置き換えることはできません。

更新

  1. 何のモック関与はありません。テストは終わりから終わりです。
  2. 私は積分テストのための生産設定に近づきたいので、統合テストにはメモリ内DBは使用されていません。

答えて

1

テストコードをラップするトランザクションにRESTハンドラメソッドを参加させることはできませんが、それは不可能です。ただし、DBUnitを使用して、テストの前および/または後にデータベースをクリーンな状態にすることができます。

私は特に、魅力的なアノテーション駆動のSpringとの統合のためにSpring Test DBUnit libraryを使用することをお勧めします。

また、Dockerを使用してデータベースをプロビジョニングすることをお勧めします。ローカルデータベースに依存することは、ビルドプロセスに外部依存関係があり、CIサーバーと各devマシン。私は以前にOvercastを使用しました。ここにはfine example of how to use it with Dockerがあります。

+0

私も同様の結論に達しました。ドッカーチップのおかげです。私たちはコードで多くの手続き(レガシー)を使用する傾向があるので、DBユニットは私の選択肢ではありません。私はドッカー+オラクルが行く方法だと思います。 – ArunM

+1

プロシージャでDBUnitを使用できなくなるのはなぜですか?スクリプト(schema.sqlなど)を使用するか、移行ツールを実行して、スイートの前のDB(プロシージャを含む)を初期化します。その後、DBUnitを使用してデータを入力して検証できます。私を信じて、そこに行って、それをやった:) –

3

私は多くのSpring + Jersey2プロジェクトで以下の設定を使用していますが、正常に動作します。

  • 使用JerseyTestとあなたのRESTコントローラ
  • であなたのサービスを模擬するために、あなたのテストクラス
  • 使用またはでそれを拡張するには、これが重要です。メモリ内のデータベース(私はHSQLDBが好ましい)を使用し、これをメモリ・データベース内でターゲットとするテスト・アプリケーション・コンテキストを作成します。したがって、データの完全性などを気にする必要はありません。
  • configure()メソッドをオーバーライドしてJerseyTestに設定し、モックを挿入し、RESTコントローラの関連サービスをJersey Contextにバインドします。ここで

例です。

@Override 
protected Application configure() { 
    // Bind factories of classes to be mocked. 
    AbstractBinder binder = new AbstractBinder() { 
     @Override 
     protected void configure() { 
      bindFactory(MockCrawlerManagerFactory.class).to(CrawlerManager.class); 
      bindFactory(MockUrlQueueServiceFactory.class).to(UrlQueueService.class); 
      bindFactory(MockSitemapServiceFactory.class).to(SitemapService.class); 
      bindFactory(MockCrawlerServiceFactory.class).to(CrawlerService.class); 
      bindFactory(MockUrlContentServiceFactory.class).to(UrlContentService.class); 
      // Other services to mock .... 
     } 
    }; 

    // This is your main Spring application 
    ApplicationContext context = new AnnotationConfigApplicationContext(Bootstrap.class); 

    // And create your Jersey context here, register REST controller to Jersey context 
    return new ResourceConfig().registerClasses(RestController.class, JacksonJsonProvider.class, JacksonJaxbJsonProvider.class) 
      .packages("com.company.foo.crawler.rest", "com.company.foo.crawler.exception").register(binder).property("contextConfig", context); 
} 
  • やテストを書き始める:)

サンプルテスト:

@Test 
    public void testCreateCrawlerWithNoConfiguration() throws ExecutionException, InterruptedException { 
    String mockUrl = "/version/" + VERSION + "/crawlers"; 
    Map<String, Object> data = new HashMap<>(); 
    data.put("configurationId", "null"); 
    data.put("startUrl", "http://blog.ahmetbutun.net"); 
    Future<Response> asyncRes = target(mockUrl).request(MediaType.APPLICATION_JSON_TYPE).header("userId", MOCK_CRAWLER_VALID_USER_ID).header("token", AUTHENTICATION_HEADER) 
      .async().post(Entity.json(data)); 

    RestResponse response = asyncRes.get().readEntity(RestResponse.class); 

    Assert.assertNotNull(response); 
    Assert.assertEquals(AppConstants.ERROR_CODE_INVALID_CONFIGURATION_ID_EXCEPTION, response.getStatusCode()); 
    Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), response.getMessage().getStatus()); 
} 

・ホープ、このことができます。

+0

答えをありがとう。私のテストは終わりを迎えます。つまり、嘲笑はありません。私はまた、実際のデータベースに対してテストするのが好きなので、oracleローカルデータベースを使って統合テストを行っています。私が直面する問題は、クライアントコードが別のスレッドで実行されるため、「テスト」トランザクションを認識しないことです。 – ArunM

2

ちょうど私の2セントを与える。スタックには特定のものがありますので、私だけかもしれないし、スタックに合わないかもしれません。

DB操作を実行するためにいくつかのORMフレームワークを使用していると仮定しています。私のテストでセッションを作成すると、私の休止状態をメモリH2にポイントします(私のhbm config on test point H2へ)。

私はデータベースのマイグレーションにliquibaseを使用しています。テストでは、これらのH2データベースを指しています(これはテストの設定から行うことができます)。私のDAOは、操作のためにこのDBを使用します。ここで私は自分のDB操作をテストし、アサーションも作成できます。

+0

ありがとう。私が下で言ったように。私はオラクルを使った。しかし、私が直面している実際の問題は、クライアントコードと実際の残りの呼び出しが同じトランザクションで発生することを確認する方法です。 – ArunM

+1

私は@ArunMを理解するために、クライアントをテストする必要があります---> [サーバー(REST API)---> DBロジックとDBトランザクション]>クライアントへの応答、通常はテストはクライアントの権利です。サーバー上のリソース駆動型トランザクションには決して参加できません。 –

+0

はい、あなたは正しいです。それは決してリソース駆動型トランザクションの一部ではありません。しかし、SpringはMockMvcを使ってこの問題に対処する解決策を持っています。私はジャージー同等のものを探しています。つまり、テストごとにデータベースを手動でクリーンアップする必要はありません。 。 – ArunM

関連する問題