基于JPA的JUnit测试最佳实践

问题描述 投票:30回答:5

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

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

java maven-2 jpa junit testng
5个回答
16
投票

您可能想尝试mockito。测试工作如下:

您使用嘲笑来“实现” EntityManager。您可以使用模仿的方法而不是实际的代码来说“如果应用程序调用getReference(),则返回此对象”。在后台,mockito将创建一个代理实例,该实例拦截Java方法调用并返回您指定的值。调用其他方法将返回null

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

由于您不使用真实的EM,所以您不需要真实的persistence.xml

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

某些其他链接可能会有所帮助:


5
投票

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

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

我们的测试方法基于针对持久层的Spring测试框架:交易中测试。我们的应用程序是基于Spring的,但是这种方法对于想要利用Spring测试类的任意应用程序同样可用。本质是,每个测试都在一个永不提交的事务中运行,并且最后(在tearDown中)它会自动回滚。这样可以很好的,透明的方式解决数据污染和测试依赖性的问题。

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

我们仍然使用legacy support for JUnit 3.8,但JUnit 4的新Spring TestContext Framework看起来很吸引人。

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

Spring DI帮助简化和自我描述的测试,但这不是关键功能。


4
投票

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

并且正如topchef指出的那样,spring的基于事务的单元测试很棒。


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"/>

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 Entity Repository。或者,您可以使用不同的弹簧轮廓(一个用于测试,另一个用于生产),最终将允许您执行相同的操作。我使用的是这种解决方案。检查上面的URL以获取更多详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.