基于JPA的JUnit测试最佳实践

时间:2022-09-11 13:53:17

This is a bit of an odd question, but it has been bothering me for a few months now. I have built a JPA-based web application using Wicket + Hibernate (built with Maven), and want to test the DAO layer directly. I created a specific src/test/resources/META-INF/persistence.xml file that I used for testing, but have been running into conflicts with WTP and the like. To get around these issues, I created a separate test project where the unit tests live. Is there a better way to manage unit tests for a JPA project without having duels between persistence files?

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

Addendum: Would other test frameworks (TestNG, for example) make this any easier?

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

4 个解决方案

#1


16  

You may want to try mockito. The test works like this:

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

You use mockito to "implement" EntityManager. Instead of the real code, you use the methods of mockito to say "if the application calls getReference(), then return this object". In the background, mockito will create a proxy instance which intercepts the Java method calls and returns the values which you specify. Calls to other methods will return null.

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

Mocking things like createQuery() works the same way but you first need to create a mockup of Query and then use the same approach as in getReference() (return the query mockup).

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

Since you don't use a real EM, you don't need a real persistence.xml.

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

A much more simple solution would be if you could set some property to change the name of the persistence.xml file but I don't think that this is possible.

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

Some other links that may help:

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

#2


5  

We use dual persistence.xml files for production and test runtimes but it is a classpath related issue only (we use Eclipse but do not rely on WTP plugins heavily). The only difference between the two is that the production version doesn't contain entity definitions.

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

We don't use a mocking framework to test JPA as this wouldn't add any value to our tests. The tests do run real data access with JPA that talks to PostgreSQL database.

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

Our approach to tests is based on Spring test framework for persistence layer: in-transaction testing. Our application is Spring-based but this approach is equally usable for arbitrary applications that want to take advantage of Spring test classes. The essence is that each test runs within a single transaction that never commits and at the end (in tearDown) it is automatically rolled back. This solves the problem of data pollution and test dependency in very nice unobtrusive and transparent way.

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

The Spring test framework is flexible to allow multi-transaction testing but these are special cases that constitute not more than 10% of tests.

Spring测试框架可灵活地允许多事务测试,但这些特殊情况构成的测试不超过10%。

We still use legacy support for JUnit 3.8 but new Spring TestContext Framework for JUnit 4 looks very attractive.

我们仍然使用JUnit 3.8的遗留支持,但JUnit 4的新Spring TestContext框架看起来非常有吸引力。

For setting up in-transaction test data we use in-house utility class that constructs business entities. Since it's shared between all tests the overhead to maintain and support it is greatly outweight by the benefits of having standard and reliable way to setup test data.

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

Spring DI helps to make tests concise and self-descriptive but it's not a critical feature.

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

#3


4  

Using Spring and Spring's unit testing is the best way to go. With spring, you don't require two persistence.xml's as your persistence.xml has nothing in it, everything is specified by spring (all we specify in our persistence.xml is the persistence-unit name) and thus you can change database configuration etc with spring.

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

And as topchef pointed out, spring's transaction based unit testing is great.

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

#4


0  

As mentioned here : http://www.devx.com/java/Article/36785/1954, you can remove the following lines from your project's .settings/org.eclipse.wst.common.component to avoid deploying test resources with the web app.

如上所述:http://www.devx.com/java/Article/36785/1954,您可以从项目的.settings / org.eclipse.wst.common.component中删除以下行,以避免使用网络应用。

<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>

#1


16  

You may want to try mockito. The test works like this:

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

You use mockito to "implement" EntityManager. Instead of the real code, you use the methods of mockito to say "if the application calls getReference(), then return this object". In the background, mockito will create a proxy instance which intercepts the Java method calls and returns the values which you specify. Calls to other methods will return null.

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

Mocking things like createQuery() works the same way but you first need to create a mockup of Query and then use the same approach as in getReference() (return the query mockup).

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

Since you don't use a real EM, you don't need a real persistence.xml.

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

A much more simple solution would be if you could set some property to change the name of the persistence.xml file but I don't think that this is possible.

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

Some other links that may help:

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

#2


5  

We use dual persistence.xml files for production and test runtimes but it is a classpath related issue only (we use Eclipse but do not rely on WTP plugins heavily). The only difference between the two is that the production version doesn't contain entity definitions.

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

We don't use a mocking framework to test JPA as this wouldn't add any value to our tests. The tests do run real data access with JPA that talks to PostgreSQL database.

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

Our approach to tests is based on Spring test framework for persistence layer: in-transaction testing. Our application is Spring-based but this approach is equally usable for arbitrary applications that want to take advantage of Spring test classes. The essence is that each test runs within a single transaction that never commits and at the end (in tearDown) it is automatically rolled back. This solves the problem of data pollution and test dependency in very nice unobtrusive and transparent way.

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

The Spring test framework is flexible to allow multi-transaction testing but these are special cases that constitute not more than 10% of tests.

Spring测试框架可灵活地允许多事务测试,但这些特殊情况构成的测试不超过10%。

We still use legacy support for JUnit 3.8 but new Spring TestContext Framework for JUnit 4 looks very attractive.

我们仍然使用JUnit 3.8的遗留支持,但JUnit 4的新Spring TestContext框架看起来非常有吸引力。

For setting up in-transaction test data we use in-house utility class that constructs business entities. Since it's shared between all tests the overhead to maintain and support it is greatly outweight by the benefits of having standard and reliable way to setup test data.

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

Spring DI helps to make tests concise and self-descriptive but it's not a critical feature.

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

#3


4  

Using Spring and Spring's unit testing is the best way to go. With spring, you don't require two persistence.xml's as your persistence.xml has nothing in it, everything is specified by spring (all we specify in our persistence.xml is the persistence-unit name) and thus you can change database configuration etc with spring.

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

And as topchef pointed out, spring's transaction based unit testing is great.

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

#4


0  

As mentioned here : http://www.devx.com/java/Article/36785/1954, you can remove the following lines from your project's .settings/org.eclipse.wst.common.component to avoid deploying test resources with the web app.

如上所述:http://www.devx.com/java/Article/36785/1954,您可以从项目的.settings / org.eclipse.wst.common.component中删除以下行,以避免使用网络应用。

<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>