0

关于在(EJB 3.0)EJB 集成测试期间通过其原始 POJO API 使用 junit 注入替代数据源的快速问题。

我一直在将原始 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. 我的一个(非常糟糕的)想法是只在包私有的服务中的 Connection 上提供一个设置器。这样,我的 junit 测试可以在执行之前设置连接。然后,在应用服务器环境中,将使用注入的 DS。虽然不漂亮。
  2. 我已经查看了 ejb3unit (BaseSessionBeanFixture) 并正在考虑这一点。
  3. 我也明白我可以在 junit 中创建一个 EJB 容器并在容器中运行。问题是,我想使用简单的 junit 测试并针对 POJO(而不是 EJB)来测试基本功能。
  4. 我知道这可以在春天完成(我有点 EJB 新手),并且正在考虑使用 spring 配置连接 EJB。

那里有很多信息,但没有具体信息(主要是 JPA)。不过,在其他地方有一些关于 SO 的好指针。

提前致谢。

4

2 回答 2

0

我的建议:

  1. 删除该conn字段,并始终使用ds.getConnection()(and )。conn.close()在您的单元测试环境中,您可以模拟 DataSource/Connection(或以其他方式提供获取并提供连接到测试数据库的“真实”对象)。
  2. 向 EJB 类添加一个 setter。事实上,你可以对注入的方法进行注解,这样你的容器和单元测试环境就更接近了。您说添加 setter 会“非常糟糕”,但我不知道为什么;setter 非常符合依赖注入的精神。我同意将 setter 添加到业务接口是没有意义的,但是在 bean 类中添加一个似乎很好。

#2 的例子:

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

这是为您的服务提供可注入连接(仅包私有)的附加样板的骨架,以便 EJB 可用作应用程序容器中的 EJB,也可用作 POJO,用于使用本地可配置连接进行 junit 测试。请注意,还有额外的样板,我们依靠调用 #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 回答