2016-06-16 22 views
1

私は、GET、POST、UPDATE、DELETEという4つのメソッドでRestサービスを作成しました。 これらのメソッドは、データベースに接続してデータを取得および格納します。JAXRS + JerseyTest RESTサービスのテスト

今、それぞれの方法をテストしたいと思います。私はこれに対してJersey Test Frameworkを使用しました。そして、実際にデータベースを呼び出すコードを削除する限り、それは機能しています。データベースを呼び出すコードを残すと、データベースに接続できないという例外がスローされます。

編集:私はいくつかの研究を行い、依存性注入を使用しました。 dbコールは別のクラスに移動されますが、私はまだ何か間違っています。

DatabaseResults。このクラスでは、DBへの呼び出しが行われます。

public class DatabaseResults { 

private final String getQuery = "SELECT * FROM movies"; 
private Connection connection = null; 
private PreparedStatement pstmt = null; 
private final ArrayList<Movie> jsonList = new ArrayList<>(); 

public JSONObject getAllMovies() throws SQLException { 

    try { 
     ComboPooledDataSource dataSource = DatabaseUtility.getDataSource(); 
     connection = dataSource.getConnection(); 

     pstmt = connection.prepareStatement(getQuery); 
     ResultSet rs = pstmt.executeQuery(); 

     while (rs.next()) { 
      jsonList.add(new Movie(rs.getString(1), rs.getString(2), rs.getString(4), rs.getString(3))); 
     } 

    } catch (SQLException ex) { 
     System.out.println(ex); 
     System.out.println("Could not retrieve a connection"); 
     connection.rollback(); 
    } finally { 
     connection.close(); 
    } 

    JSONObject jsonObject = new JSONObject(); 
    jsonObject.put("movies", jsonList); 

    return jsonObject; 
    } 
} 

REST方式

@Path("movies") 
public class MoviesResource { 

.... 
private DatabaseResults dbResults = null; 

public MoviesResource() { 
    this(new DatabaseResults()); 
} 

MoviesResource(DatabaseResults dbr){ 
    this.dbResults = dbr; 

} 
.... 
@GET 
@Produces(MediaType.APPLICATION_JSON) 
public Response getAllMovies() throws JSONException, SQLException { 

    return Response.status(200).entity(dbResults.getAllMovies().toString()).build(); 
} 

が含まれているMoviesResource Testクラス

@RunWith(MockitoJUnit44Runner.class) 
public class MovieResourceTest extends JerseyTest { 

JSONObject jsonObject = new JSONObject(); 

@Mock 
DatabaseResults dbr; 

@Before 
public void setup() throws SQLException{ 
    jsonObject.put("id", "hello"); 

    when(dbr.getAllMovies()).thenReturn(jsonObject); 
}   

Client client = ClientBuilder.newClient(); 
WebTarget target = client 
     .target("http://localhost:9998/RestServiceMovies/resources"); 

@Override 
protected Application configure() { 
    return new ResourceConfig(MoviesResource.class); 
} 

@Test 
public void getAllMoviesTest() throws SQLException { 

    String responseGetAllMovies = target("/movies").request().get(String.class); 

    Assert.assertTrue("hello".equals(responseGetAllMovies)); 
} 

この時点で、私はそれが呼び出しを行うgetAllMovies()方法をテストするとき、私はまだテストを実行することができますが、 jsonObjectを返すのではなく、実際のデータベースに転送します。

モックオブジェクトとMovieResourceクラスのコンストラクタの間に接続がないと感じましたか?

+0

RESTサービスが単一責任の原則に違反しているため、これはテストするのが難しいです。データベース・ロジックを別のクラスにカプセル化すると、そのクラスを簡単にモックしてRESTサービスを単独でテストできます。別の一般的なアプローチは、ユニットテストを実行して統合テストを実行することです。すなわち、メモリ内のデータベースを構成し、何も嘲笑しない。 – DavidS

+0

だから私は別のクラスに自分のデータベースロジックをカプセル化しました。私はMockitoを使ってデータをモックしたいのですが、私は実際に私の 'getAllMovies'メソッドが模擬クラスを使うべきだとはどういうことがわかりません... – RSSD

+0

これにはいくつかのアプローチがあります。あなたのRESTサービスがいくつかのプライベートフィールドにアクセスしているとします。 'moviesDatabase'です。このオブジェクトまたはそのメソッドをモックしたいので、使用する 'moviesDatabase'があるRESTサービスに何らかの方法を伝える必要があります。あなたのオプションは:(1)コンストラクタインジェクション(2)フィールドをpackage-privateにして、それを直接設定する(3)DaggerやWeldのようなファンシー依存性注入フレームワークを使用する。 – DavidS

答えて

2

あなたはクラスとして

new ResourceConfig(MoviesResource.class) 

をあなたのリソースを登録するときは、インスタンスを作成するためにジャージーを語っています。 DIを設定していない場合は、引数なしのコンストラクタが呼び出されます。引数なしのコンストラクタでは、サービスを自分で作成するだけです。あなたのモックについては何も知らない。

代わりに行うべきことは、リソースクラスをインスタンスとして登録することです。そうすれば、モックをコンストラクタに渡すことができます。

MockitoAnnotations.initMocks(this); 
return new ResourceConfig() 
     .register(new MoviesResource(dbr)); 

Mockitoランナーは使用しないでください。代わりにMockitoAnnotations.initMocksメソッドを使用します。そうすれば、@Mockが注入されたときに制御することができます。ランナーを使用すると、Mockito注入が起こる前にconfigureメソッドがフレームワークによって呼び出されるため、注入は時間内に行われません。

+0

ありがとう!私はMockitoランナーを削除し、 'MockitoAnnotations.initMocks(this);を追加しました。新しいResourceConfig()。register(new MoviesResource(dbr)) 'コードを返します。 – RSSD

+1

あなたの権利は 'init'ではなく' initMocks'でなければなりません:-) –