基于JPA的JUnit测试最佳实践

时间:2009-08-05 17:58:37

标签: java maven-2 jpa junit testng

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

附录:其他测试框架(例如TestNG)是否会使这更容易?

5 个答案:

答案 0 :(得分:16)

您可以尝试mockito。测试的工作方式如下:

您使用mockito来“实施”EntityManager。您可以使用mockito的方法来代替实际代码,“如果应用程序调用{​​{1}},则返回此对象”。在后台,mockito将创建一个代理实例,该实例拦截Java方法调用并返回您指定的值。调用其他方法将返回getReference()

null这样的模拟工作方式相同,但您首先需要创建createQuery()的模型,然后使用与Query中相同的方法(返回查询模型)。 / p>

由于您不使用真正的EM,因此您不需要真正的getReference()

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

其他一些可能有用的链接:

答案 1 :(得分: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有助于使测试简洁且具有自我描述性,但它不是一个关键特性。

答案 2 :(得分:4)

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

正如topchef指出的那样,Spring基于交易的单元测试非常棒。

答案 3 :(得分: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"/>

答案 4 :(得分:0)

您可以:

  1. 有几个持久性单元
  2. 拥有几个persistence.xml并在测试中将其复制,并在以后还原它们
  3. 在测试中设置您自己的属性,并使用Mockito返回自定义实体管理器工厂
  4. 使用spring: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();
}

现在,每个测试都有一个实体管理器。使用嘲笑将其注入到需要的地方。

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