0

junit を使用して未加工の POJO API を介して (EJB 3.0) EJB の統合テスト中に代替データソースを注入することについての簡単な質問です。

生の POJO サービスを EJB3 セッション Bean に変換しています。そうすることは、POJO に直接注釈を付けることを意味するだけです。サービスには、既存の junit 統合テスト (実際のテスト データベースにクエリを実行するメソッドの結果をチェックする) も付随しています。

これらのサービスのいくつかは、直接の java.sql.Connection を必要とするため、注入された DataSource を介してこれを構成するつもりです。これの意図は、Bean をアプリケーション サーバー (たまたま WLS) に直接デプロイできるようにすることです。ただし、既存の統合テストも引き続き機能することを望んでいます。これらのテストは独自のテスト データベースに対して実行されるため、(POJO/非コンテナー環境で) 統合テストを実行するときにテスト構成を挿入できる必要があります。

質問は:

EJB を設定したら、コンテナ内で操作せずに注入された Bean をオーバーライドする方法はありませんか?

別の言い方をすれば、未加工の POJO 統合テストを実行するときに、新しい JNDI 構成を挿入する簡単な方法はありませんか?

サービスの例は次のようになります。

@Stateless(mappedName="MyInterface")
public class MyClassImpl implements MyInterface {
    ... 
    @Resource(name="jdbc/MyAppServerDataSourceJNDIName")
    DataSource ds;
    Connection conn;
...
}

注意: DataSource と Connection をサービスに残すつもりはありません。有機的にリファクタリングする前に、適切に動作するようにしたいだけです。

私が検討している解決策:

  1. 私が持っている1つの(かなりひどい)概念は、パッケージプライベートであるサービスの接続にセッターを提供することです。このようにして、junit テストは実行前に接続を設定できます。次に、アプリサーバー環境で、挿入された DS が使用されます。かわいくないけど。
  2. 私は ejb3unit (BaseSessionBeanFixture) を見て、それを検討しています。
  3. また、junit で EJB コンテナーを作成し、コンテナー内で実行できることも理解しています。問題は、簡単なjunitテストを使用してPOJO(EJBではなく)に対して基本機能をテストしたいということです。
  4. 私はこれが春にできることを知っており(私は少しEJBの初心者です)、春の構成を使用してEJBを配線することを検討しています。

そこには多くの情報がありますが、具体的なものはありません (主に JPA)。ただし、SOの他の場所にいくつかの良い指針があります。

前もって感謝します。

4

2 に答える 2

0

私の推奨事項:

  1. connフィールドを削除し、一貫してds.getConnection()(および) を使用します。conn.close()単体テスト環境では、DataSource/Connection をモック化できます (または、テスト データベースに接続された "実際の" オブジェクトを取得および提供できます)。
  2. EJB クラスにセッターを追加します。実際、インジェクションのメソッドにアノテーションを付けて、コンテナーと単体テスト環境をさらに近づけることができます。セッターを追加するのは「かなりひどい」と述べていますが、その理由はわかりません。セッターは、依存性注入の精神に非常に忠実です。ビジネス インターフェイスにセッターを追加しても意味がないことには同意しますが、Bean クラスにセッターを追加しても問題ないようです。

#2 の例:

@Resource(name="jdbc/MyAppServerDataSourceJNDIName")
public void setDataSource(DataSource ds) {
    this.ds = ds;
}
于 2012-11-08T22:44:47.563 に答える
0

これは、EJB がアプリケーション コンテナ内の EJB としてだけでなく、ローカルで設定可能な接続を使用した JUnit テスト用の POJO としても使用できるように、サービスへの注入可能な接続を提供する追加のボイラープレートのスケルトンです (パッケージ プライベートのみ)。追加の定型文があり、#closeConnection を呼び出すテストに依存して適切に管理していることに注意してください。

この解決策は、元の質問と bkail の応答を思い起こさせます。

@Stateless(mappedName = "MyClass")
...
public class MyClass {

  // DataSource as configured for app-server environment
  @Resource(name="app-dataSource")
  private DataSource appDataSource;

  private Connection conn;

  /**
   * Injectable {@code Connection} for injection by unit tests.
   */
  /*package-private*/ void setConnection(Connection conn) {
      this.conn = conn;
  }

  /**
   * Get {@code Connection}. Use injected Connection if supplied, otherwise
   * obtain one from the datasource. Client is responsible for closing this
   * through call to #closeConnection (only!).
   */
  final Connection getConnection() {
    if (this.conn != null) {
      return this.conn;
    } else {
      //Needs exception handling
      //
      return getDataSource().getConnection)
    }
  }

  /*package-private*/ final void closeConnection(Connection conn) {
    if (conn != null && conn != this.conn) {
      try{
        conn.close();
      } catch ... {}
    }
  }

  /*
   * Accessor for the {@code DataSource}.
   * @return the DataSource
   */
  private DataSource getDataSource() {
    if (ds == null) {
      ...
      ds = (DataSource) ctx.lookup(jndiName);
      ...
    }
    return ds;
  }

  ...
}

public class TestMyClass {
  private Connection conn = null;

  @BeforeClass
  public void setUpBeforeClass() throws Exception {
    ...
    conn = DriverManager.getConnection(...);
  }

  @Test
  public void testMyMethod {
    MyClass mc = new MyClass();
    mc.setConnection(conn);           // Set our own connection

    // do test stuff
    ...
  }
  ...
}
于 2013-10-04T09:45:04.173 に答える