30

这是一个有点奇怪的问题,但它已经困扰了我几个月了。我已经使用 Wicket + Hibernate(使用 Maven 构建)构建了一个基于 JPA 的 Web 应用程序,并且想直接测试 DAO 层。我创建了一个用于测试的特定 src/test/resources/META-INF/persistence.xml 文件,但一直与 WTP 等发生冲突。为了解决这些问题,我创建了一个单独的测试项目,单元测试位于其中。有没有更好的方法来管理 JPA 项目的单元测试,而无需在持久性文件之间进行决斗?

附录:其他测试框架(例如,TestNG)会让这更容易吗?

4

5 回答 5

16

您可能想尝试mockito。测试是这样工作的:

您使用 mockito 来“实施” EntityManager。代替真正的代码,您使用 mockito 的方法说“如果应用程序调用getReference(),则返回这个对象”。在后台,mockito 将创建一个代理实例,它拦截 Java 方法调用并返回您指定的值。对其他方法的调用将返回null

模拟类似createQuery()的工作方式相同,但您首先需要创建一个模型,Query然后使用与中相同的方法getReference()(返回查询模型)。

由于您不使用真正的 EM,因此您不需要真正的persistence.xml.

一个更简单的解决方案是,如果您可以设置一些属性来更改persistence.xml文件的名称,但我认为这是不可能的。

其他一些可能有帮助的链接:

于 2009-08-05T19:03:16.107 回答
5

我们在生产和测试运行时使用双重persistence.xml文件,但这只是与类路径相关的问题(我们使用 Eclipse,但不严重依赖 WTP 插件)。两者之间的唯一区别是生产版本不包含实体定义。

我们不使用模拟框架来测试 JPA,因为这不会为我们的测试增加任何价值。测试确实使用与 PostgreSQL 数据库对话的 JPA 运行真实数据访问。

我们的测试方法基于持久层的 Spring 测试框架:事务内测试。我们的应用程序是基于 Spring 的,但这种方法同样适用于希望利用 Spring 测试类的任意应用程序。本质是每个测试都在一个从不提交的事务中运行,最后(在拆卸中)它会自动回滚。这以非常好的不显眼和透明的方式解决了数据污染和测试依赖的问题。

Spring 测试框架很灵活,可以进行多事务测试,但这些是不超过 10% 测试的特殊情况。

我们仍然使用对 JUnit 3.8 的旧支持,但 JUnit 4 的新Spring TestContext Framework看起来非常有吸引力。

为了设置事务中测试数据,我们使用构建业务实体的内部实用程序类。由于它在所有测试之间共享,因此维护和支持它的开销大大超过了使用标准和可靠的方法来设置测试数据的好处。

Spring DI 有助于使测试简洁和自我描述,但它不是一个关键特性。

于 2009-08-05T21:27:05.177 回答
4

使用 Spring 和 Spring 的单元测试是最好的方法。使用spring,您不需要两个persistence.xml,因为您的persistence.xml中没有任何内容,所有内容都由spring指定(我们在persistence.xml中指定的只是持久性单元名称),因此您可以更改数据库配置等与春天。

正如topchef 所指出的,spring 的基于事务的单元测试很棒。

于 2009-08-06T09:05:33.977 回答
0

如此处所述:http: //www.devx.com/java/Article/36785/1954,您可以从项目中删除以下行,.settings/org.eclipse.wst.common.component以避免使用 Web 应用程序部署测试资源。

<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>
于 2011-12-16T11:32:13.920 回答
0

你可以:

  1. 有几个持久性单元
  2. 有几个persistence.xml并在测试时复制它们,稍后恢复它们
  3. 在测试中设置您自己的属性,并使用 mockito 返回您的自定义实体管理器工厂
  4. 使用弹簧:https ://www.baeldung.com/spring-testing-separate-data-source

前两个选项是所有建议问题中讨论最多的选项,也是迄今为止我最不喜欢的选项。

解决方案 3. 看起来像这样:

private EntityManager entityManager;

private static EntityManagerFactory entityManagerFactory;

@BeforeClass
public static void mainTestInitClass() {
    Properties pros = new Properties();
    // Override production properties
    pros.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
    pros.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
    pros.setProperty("hibernate.connection.username", "sa");
    pros.setProperty("hibernate.connection.url", "jdbc:h2:mem:some_test_db;DB_CLOSE_DELAY=-1;MVCC=TRUE;DATABASE_TO_UPPER=false");
    pros.setProperty("hibernate.hbm2ddl.auto", "create");

    entityManagerFactory = Persistence.createEntityManagerFactory("your_unit", pros);
}

@Before
public void mainTestORMSetUp() throws Exception {
    this.entityManager = entityManagerFactory.createEntityManager();
}

现在您有一个可用于每个测试的实体管理器。使用 mockito 在需要的地方注入它。

解决方案 4:使用 Spring Data+Spring Boot 设置 JPA,因此您不再需要实体工厂,您只需使用两个不同的 application.properties(一个用于 main,一个用于测试),然后使用您定义的 Spring实体存储库。或者,您可以使用不同的弹簧轮廓(一个用于测试,另一个用于生产),最终允许您执行相同的操作。这个解决方案是我使用的。检查上面的 URL 以获取更多详细信息。

于 2020-02-21T21:45:17.683 回答