使用 JPA2 时如何对 EJB 进行单元测试?

Posted

技术标签:

【中文标题】使用 JPA2 时如何对 EJB 进行单元测试?【英文标题】:How to unit testing EJBs when using JPA2? 【发布时间】:2011-04-19 13:22:54 【问题描述】:

您将如何对使用 JPA 的 EJB 进行单元测试?例如,如果我有一个 Order 实体和 OrderEJB,它应该计算订单的总数(定义如下),我将如何在不接触数据库的情况下对 EJB 进行单元测试?此外,您将如何为您的实体定义值,以便您可以断言预期的计算?下面是一些示例代码...

@Entity
public class Order 
    @Id
    private long OrderId;
    private LineItem[] items;

还有一个orderEJB

@Stateless
public class OrderEJB 
    EntityManager em;
    public double calculateOrderTotal(long orderId)  .. 

如果我无法访问数据库,您将如何对 calculateOrderTotal 方法进行单元测试?我不想实现 DAO,因为我正试图摆脱这种方法。

感谢您的帮助。

【问题讨论】:

【参考方案1】:

OrderEJB 和 Order 和 LineItem 的一般理论不是(如果我们忽略注释)只是 POJO,因此可以在独立的 JUnit 中进行测试吗?我们需要模拟 EntityManager,大概在

 calculateOrderTotal()

你有一些概念上的代码

 em.giveMeThisOrder(orderId)

你只是嘲笑这个。然后,您正在测试的业务逻辑由 Mock 返回的内容驱动。这样做的关键是您必须使用一个好的模拟框架,例如 JMock。在您说的任何给定测试中(显然不是这种语法):

 EntitiyManager mockEm = // create the mock
 mockEm.check(that you are called with and order Id of 73)
 mockEm.please( when someone calls giveMeThisOrder return then **this** particular order)

因此,在每个测试中,您都可以准确地创建执行计算代码某些方面所需的顺序。您可能有很多这样的测试可以推动您计算的所有边缘和角落情况。

这里的关键思想是单元测试意味着没有外部依赖,例如数据库。集成测试可以使用真实的数据库。正确进行模拟可能会很麻烦,创建这些 Order 实例可能很枯燥,但它确实会使未来的测试更快。

我也赞成进行早期集成测试——这样你会发现完全不同的错误。

【讨论】:

但是,如果您不知道数据将是什么,您如何断言计算是正确的?您是否需要使用集成测试来执行此操作?也许我把两者混为一谈了,我对集成测试和单元测试之间的区别有点困惑...... 确实知道数据会是什么,我会更新答案来解释。 对,但是如何注入模拟的EntityManager?运行时容器在幕后执行此操作,这对我来说很方便,因为我是 Java EE 的新手,但我不知道如何在测试期间注入。例如,我有一个带有注入的 EntityManager (@PersistenceContext) 的 JAX-RS 对象 (@Path),但是 Jersey servlet 在实例化期间没有给我的测试提供钩子,对吧?【参考方案2】:

您尝试过 OpenEjb 吗? - 如果您在嵌入式模式下设置,您几乎可以从 eclipse 运行单元测试。我之前已经为单元测试模拟了实体管理器注入等,但后来变得乏味。使用 openejb,您可以用更少的设置完成它。 http://openejb.apache.org/

【讨论】:

当然,这归结为你想去多孤立:) - 恕我直言,你需要创建的脚手架使其如此孤立是不值得的。我宁愿加入 openejb 和 hsqldb 来对我的 ejb 进行单元测试,而不必担心到处创建模拟。再次只是我的看法 - 可能与你们中的很多人不同,我不知道。也忘记将其添加到原始帖子中 - adam-bien.com/roller/abien/entry/how_to_unit_test_ejb 这是一种非常有效的集成测试方法。只是 OP 明确询问了单元测试(而不是触及数据库)。【参考方案3】:

这是我的工作:

首先,您需要为您的测试设置一个内存数据库。它就像一个普通的数据库一样工作,但它不存储在磁盘上。 Derby 和 HsqlDB 都支持这一点。

在您的单元测试中,手动创建一个 EntityManager,并将其注入您的 EJB 实例。您可能需要保留对 EntityManager 的引用,以便管理事务,如下所示:

em.getTransaction().begin();
myEjb.doSomething(x, y);
em.getTransaction().commit();

【讨论】:

这不是单元测试(这是一种有效的集成测试方法,但它不是单元测试)。 好吧,如果我自己测试单个 EJB,我会称其为单元测试。您可能会说,如果我将它连接到持久性提供程序,那么我不会“单独”测试它 - 我想这也是一个有效的职位,但我没有得到足够的报酬来分裂头发. 对,但是如何将它注入到 EJB 实例中?

以上是关于使用 JPA2 时如何对 EJB 进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis - 如何对结果图进行单元测试?

在 Angular 中使用 Jasmine 使用 *ngIf 指令时,如何对元素是不是可见进行单元测试

手把手教你如何进行 Golang 单元测试

MockEJB - JUnit Mockito - 无法在第二个单元测试中重新绑定模拟 EJB

如何对 vsix 项目进行单元测试?

如何使用 EntityType 字段对 Symfony 4 表单进行单元测试