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

Java 如何在使用JPA2时对EJB进行单元测试?,java,unit-testing,jakarta-ee,jpa-2.0,ejb-3.1,Java,Unit Testing,Jakarta Ee,Jpa 2.0,Ejb 3.1,您将如何对使用JPA的EJB进行单元测试?例如,如果我有一个Order实体和OrderEJB,该实体和OrderEJB应该计算一个订单的总数(定义如下),那么我如何在不接触数据库的情况下对EJB进行单元测试?另外,如何定义实体的值,以便可以断言预期的计算?下面是一些示例代码 @Entity public class Order { @Id private long OrderId; private LineItem[] items; } 和一个命令EJB @Statel

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

@Entity
public class Order {
    @Id
    private long OrderId;
    private LineItem[] items;
}
和一个命令EJB

@Stateless
public class OrderEJB {
    EntityManager em;
    public double calculateOrderTotal(long orderId) { .. }
}
如果我不能接触数据库,你会如何对calculateOrderTotal方法进行单元测试?我不想实现DAO,因为我正试图摆脱这种方法


感谢您的帮助。

OrderEJB、Order和LineItem(如果我们忽略注释)不就是POJO,因此可以在独立JUnit中测试吗?我们将需要模仿EntityManager,大概是在

 calculateOrderTotal()
你有一些概念上的代码

 em.giveMeThisOrder(orderId)
你只是在嘲笑这个。然后,您正在测试的业务逻辑会受到模拟结果的驱动。关键是必须使用良好的模拟框架,例如JMock。在任何给定的测试中,您都会说(显然不是用这种语法):

因此,在每个测试中,您创建的顺序正好是您需要执行计算代码某些方面的顺序。你可能会有很多这样的测试,推动所有的边缘和角落的情况下,你的计算

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

我也喜欢做早期集成测试——这样你会发现另外一类错误。

以下是我的工作:

首先,您需要为测试设置内存中的数据库。它的工作原理与常规数据库一样,但它不存储在磁盘上。Derby和HsqlDB都支持这一点

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

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

你试过OpenEjb吗?-如果您在嵌入式模式下进行设置,您几乎可以从eclipse运行单元测试。我以前曾为单元测试模拟过实体管理器注入等,但后来变得单调乏味。使用openejb,您可以用较少的设置完成此操作

这不是单元测试(这是集成测试的有效方法,但不是单元测试)。你可能会说,如果我将它连接到一个持久性提供程序,那么我就不会“单独”测试它——我想这也是一个有效的位置,但我没有得到足够的报酬来挑拨离间。对,但是你如何将它注入EJB实例?但是你如何断言计算是正确的,如果你不知道数据是什么?您需要使用集成测试来完成这项工作吗?也许我混淆了两者,我对集成测试和单元测试之间的区别有点困惑…你知道数据将是什么,我会更新答案来解释。对,但是你如何注入模拟EntityManager?运行时容器在后台执行此操作,这对我来说很方便,因为我是JavaEE新手,但我不知道如何在测试期间进行注入。例如,我有一个JAX-RS对象(@Path)和一个注入的EntityManager(@PersistenceContext),但是Jersey servlet在实例化过程中没有给我的测试提供钩子,对吗?当然,这可以归结为您希望实现的隔离程度:)-IMHO为了使它如此隔离而需要创建的支架是不值得的。我宁愿加入openejb和hsqldb来对我的EJB进行单元测试,而不必担心在任何地方都创建模拟。再说一次,这只是我的看法——也许它与你们中的许多人不同,我不知道。还忘了将其添加到原始帖子中-这是一种非常有效的集成测试方法。只是OP明确地询问了单元测试(而不是数据库)。
em.getTransaction().begin();
myEjb.doSomething(x, y);
em.getTransaction().commit();