Java JUnit 测试在 Eclipse 中通过但在 Maven Surefire 中失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3365628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JUnit tests pass in Eclipse but fail in Maven Surefire
提问by Abhinav Sarkar
I have written some JUnit tests using JUnit 4 and spring-test libraries. When I run the tests inside Eclipse then run fine and pass. But when I run them using Maven (during the build process), they fail giving a spring related error. I am not sure what is causing the problem, JUnit, Surefire or Spring. Here is my test code, spring configuration and the exception that I get from Maven:
我已经使用 JUnit 4 和 spring-test 库编写了一些 JUnit 测试。当我在 Eclipse 中运行测试时,运行良好并通过。但是当我使用 Maven 运行它们时(在构建过程中),它们无法给出与弹簧相关的错误。我不确定是什么导致了这个问题,JUnit、Surefire 还是 Spring。这是我的测试代码、spring 配置和我从 Maven 得到的异常:
PersonServiceTest.java
人员服务测试.java
package com.xyz.person.test;
import static com.xyz.person.util.FjUtil.toFjList;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.xyz.person.bo.Person;
import com.xyz.person.bs.PersonService;
import fj.Effect;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:personservice-test.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class PersonServiceTest {
@Autowired
private PersonService service;
@Test
@Transactional
public void testCreatePerson() {
Person person = new Person();
person.setName("abhinav");
service.createPerson(person);
assertNotNull(person.getId());
}
@Test
@Transactional
public void testFindPersons() {
Person person = new Person();
person.setName("abhinav");
service.createPerson(person);
List<Person> persons = service.findPersons("abhinav");
toFjList(persons).foreach(new Effect<Person>() {
public void e(final Person p) {
assertEquals("abhinav", p.getName());
}});
}
}
personservice-test.xml
人员服务-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<import resource="classpath:/personservice.xml" />
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="true">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:InMemoryDatabase;create=true" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="persistenceUnitName" value="PersonService" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect" />
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.validator.autoregister_listeners" value="false" />
<entry key="javax.persistence.transactionType" value="RESOURCE_LOCAL" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="datasource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="false" />
<bean id="beanMapper" class="org.dozer.DozerBeanMapper">
<property name="mappingFiles">
<list>
<value>personservice-mappings.xml</value>
</list>
</property>
</bean>
</beans>
Exception in Maven
Maven 中的异常
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.xyz.person.test.PersonServiceTest
23:18:51,250 WARN JDBCExceptionReporter:77 - SQL Warning: 10000, SQLState: 01J01
23:18:51,281 WARN JDBCExceptionReporter:78 - Database 'InMemoryDatabase' not created, connection made to existing database instead.
23:18:52,937 WARN JDBCExceptionReporter:77 - SQL Warning: 10000, SQLState: 01J01
23:18:52,937 WARN JDBCExceptionReporter:78 - Database 'InMemoryDatabase' not created, connection made to existing database instead.
23:18:52,953 WARN TestContextManager:429 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@359a359a] to process 'after' execution for test: method [public void com.xyz.person.test.PersonServiceTest.testCreatePerson()], instance [com.xyz.person.test.PersonServiceTest@1bc81bc8], exception [org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions on a single DataSource, no matter whether JPA or JDBC access.]
java.lang.IllegalStateException: No value for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3f563f56] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:199)
at org.springframework.orm.jpa.JpaTransactionManager.doCleanupAfterCompletion(JpaTransactionManager.java:489)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1011)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:804)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:515)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:290)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:183)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:426)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:90)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
0(ParentRunner.java:42)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:115)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:102)
at org.apache.maven.surefire.Surefire.run(Surefire.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
23:18:53,078 WARN TestContextManager:377 - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@359a359a] to process 'before' execution of test method [public void com.xyz.person.test.PersonServiceTest.testFindPersons()] for test instance [com.xyz.person.test.PersonServiceTest@79f279f2]
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions on a single DataSource, no matter whether JPA or JDBC access.
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:304)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.startTransaction(TransactionalTestExecutionListener.java:507)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:269)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:162)
at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:374)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<skipTests>${maven.test.skip}</skipTests>
<trimStackTrace>false</trimStackTrace>
<!--<parallel>methods</parallel>-->
<!-- to skip integration tests -->
<excludes>
<exclude>**/IT*Test.java</exclude>
<exclude>**/integration/*Test.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skipTests>${maven.integration-test.skip}</skipTests>
<!-- Make sure to include this part, since otherwise it is excluding Integration tests -->
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/IT*Test.java</include>
<include>**/integration/*Test.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
0(ParentRunner.java:42)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:115)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:102)
at org.apache.maven.surefire.Surefire.run(Surefire.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 15.625 sec <<< FAILURE!
Results :
Tests in error:
testCreatePerson(com.xyz.person.test.PersonServiceTest)
testCreatePerson(com.xyz.person.test.PersonServiceTest)
testFindPersons(com.xyz.person.test.PersonServiceTest)
Tests run: 3, Failures: 0, Errors: 3, Skipped: 0
回答by Richard Kettelerij
You don't need to inject a DataSource in the JpaTransactionManager since the EntityManagerFactory already has a datasource. Try the following:
您不需要在 JpaTransactionManager 中注入数据源,因为 EntityManagerFactory 已经有一个数据源。请尝试以下操作:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<parallel>classes</parallel>
<threadCount>10</threadCount>
</configuration>
</plugin>
回答by Bruno Thomas
Usually when tests pass in eclipse and fail with maven it is a classpath issue because it is the main difference between the two.
通常,当测试在 Eclipse 中通过而在 maven 中失败时,这是一个类路径问题,因为这是两者之间的主要区别。
So you can check the classpath with maven -X test and check the classpath of eclipse via the menus or in the .classpath file in the root of your project.
因此,您可以使用 maven -X test 检查类路径,并通过菜单或项目根目录中的 .classpath 文件检查 eclipse 的类路径。
Are you sure for example that personservice-test.xml is in the classpath ?
例如,您确定 personservice-test.xml 在类路径中吗?
回答by s13o
I have the similar problem, but with IntelliJ IDEA + Maven + TestNG + spring-test. (spring-testis essential of course :) ) It was fixed when I've change config of maven-surefire-pluginto disable run tests in parallel. Like this:
我有类似的问题,但使用 IntelliJ IDEA + Maven + TestNG + spring-test。(spring-test当然是必不可少的 :) )当我更改maven-surefire-plugin 的配置以禁用并行运行测试时,它已修复。像这样:
<dependency>
<groupId>junit</groupId
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
回答by Jesper R?nn-Jensen
I suddenly experienced this error, and the solution for me was to disable to run tests in parallel.
我突然遇到了这个错误,我的解决方案是禁用并行运行测试。
Your milage may vary, since I could lower number of failing tests by configuring surefire to run parallel tests by ′classes′.:
您的里程可能会有所不同,因为我可以通过将 surefire 配置为按“类”运行并行测试来减少失败测试的数量。:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12</version> <configuration> <forkMode>always</forkMode> </configuration> </plugin>
As I wrote first, this was not enough for my test suite, so I completely disabled parallel by removing the <configuration>
section.
正如我第一次写的那样,这对于我的测试套件来说还不够,所以我通过删除该<configuration>
部分来完全禁用并行。
回答by Jim Jarrett
This doesn't exactly apply to your situation, but I had the same thing -- tests that would pass in Eclipse failed when the test goal from Maven was run.
这并不完全适用于您的情况,但我有同样的事情 - 当运行来自 Maven 的测试目标时,在 Eclipse 中通过的测试失败。
It turned out to be a test earlier in my suite, in a different package. This took me a week to solve!
原来是在我的套件中进行了一个测试,在不同的包中。这花了我一周的时间才解决!
An earlier test was testing some Logback classes, and created a Logback context from a config file.
早期的测试是测试一些 Logback 类,并从配置文件创建了一个 Logback 上下文。
The later test was testing a subclass of Spring's SimpleRestTemplate, and somehow, the earlier Logback context was held, with DEBUG on. This caused extra calls to be made in RestTemplate to log HttpStatus, etc.
后来的测试是测试 Spring 的 SimpleRestTemplate 的一个子类,不知何故,保留了较早的 Logback 上下文,并打开了 DEBUG。这导致在 RestTemplate 中进行额外调用以记录 HttpStatus 等。
It's another thing to check if one ever gets into this situation. I fixed my problem by injecting some Mocks into my Logback test class, so that no real Logback contexts were created.
检查是否有人陷入这种情况是另一回事。我通过将一些 Mock 注入我的 Logback 测试类来解决我的问题,因此没有创建真正的 Logback 上下文。
回答by cartman1989
I had a similar problem, the annotation @Autowired
in the test code did not work under using the Maven command line while it worked fine in Eclipse. I just update my JUnit version from 4.4 to 4.9 and the problem was solved.
我有一个类似的问题,@Autowired
测试代码中的注释在使用 Maven 命令行下不起作用,而在 Eclipse 中运行良好。我只是将我的 JUnit 版本从 4.4 更新到 4.9,问题就解决了。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<reuseForks>false</reuseForks>
<forkCount>1</forkCount>
</configuration>
</plugin>
回答by Mitch
I had this problem today testing a method that converted an object that contained a Map
to a JSON string. I assume Eclipse and the Maven surefire plugin were using different JREs which had different implementations of HashMap
ordering or something, which caused the tests run through Eclipse to pass and the tests run through surefire to fail (assertEquals
failed). The easiest solution was to use an implementation of Map that had reliable ordering.
我今天遇到了这个问题,测试了一种将包含 a 的对象转换Map
为 JSON 字符串的方法。我假设 Eclipse 和 Maven surefire 插件使用不同的 JRE,它们具有不同的HashMap
排序实现或其他东西,这导致通过 Eclipse 运行的测试通过,而通过 surefire 运行的测试失败(assertEquals
失败)。最简单的解决方案是使用具有可靠排序的 Map 实现。
回答by simon
I had the same problem (JUnit tests failed in Maven Surefire but passed in Eclipse) and managed to solve it by setting forkModeto alwaysin the maven surefire configuration in pom.xml:
我遇到了同样的问题(JUnit 测试在 Maven Surefire 中失败但在 Eclipse 中通过)并设法通过在 pom.xml 中的 maven surefire配置中将forkMode设置为always来解决它:
##代码##Surefire parameters: http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html
Surefire 参数:http: //maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html
Edit (January 2014):
编辑(2014 年 1 月):
As Peter Perhá?pointed out, the forkMode parameter is deprecated since Surefire 2.14. Beginning from Surefire 2.14 use this instead:
就像彼得·佩尔哈?指出,forkMode 参数自 Surefire 2.14 起已弃用。从 Surefire 2.14 开始改用这个:
##代码##For more information see Fork Options and Parallel Test Execution
有关更多信息,请参阅Fork 选项和并行测试执行
回答by andrew cooke
[I am not sure that this is an answer to the original question, since the stacktrace here looks slightly different, but it may be useful to others.]
[我不确定这是对原始问题的回答,因为这里的堆栈跟踪看起来略有不同,但对其他人可能有用。]
You can get tests failing in Surefire when you are also running Cobertura (to get code coverage reports). This is because Cobertura requires proxies (to measure code use) and there is some kind of conflict between those and Spring proxies. This onlyoccurs when Spring uses cglib2, which would be the case if, for example, you have proxy-target-class="true"
, or if you have an object that is being proxied that does not implement interfaces.
当您还运行 Cobertura(以获取代码覆盖率报告)时,您可能会在 Surefire 中测试失败。这是因为 Cobertura 需要代理(以测量代码使用),并且这些代理与 Spring 代理之间存在某种冲突。这仅在 Spring 使用 cglib2 时发生,例如,proxy-target-class="true"
如果您有 ,或者您有一个没有实现接口的被代理的对象,就会出现这种情况。
The normal fix to this is to add an interface. So, for example, DAOs should be interfaces, implemented by a DAOImpl class. If you autowire on the interface, everything will work fine (because cglib2 is no longer required; a simpler JDK proxy to the interface can be used instead and Cobertura works fine with this).
对此的正常修复是添加一个接口。因此,例如,DAO 应该是接口,由 DAOImpl 类实现。如果您在接口上自动装配,一切都会正常工作(因为不再需要 cglib2;可以改为使用更简单的接口 JDK 代理,而 Cobertura 可以很好地处理这个问题)。
However, you cannot use interfaces with annotated controllers (you will get a runtime error when trying to use the controller in a servlet) - I do not have a solution for Cobertura + Spring tests that autowire controllers.
但是,您不能将接口与带注释的控制器一起使用(尝试在 servlet 中使用控制器时会出现运行时错误)——我没有针对自动装配控制器的 Cobertura + Spring 测试的解决方案。
回答by Miguel
It is most likely that your configuration files are in src/main/resources, while they must be under src/test/resourcesto work properly under maven.
您的配置文件很可能在src/main/resources 中,而它们必须在src/test/resources下才能在 maven 下正常工作。
https://cwiki.apache.org/UIMA/differences-between-running-unit-tests-in-eclipse-and-in-maven.html
https://cwiki.apache.org/UIMA/differences-between-running-unit-tests-in-eclipse-and-in-maven.html
I'm replying this after two years 'cause I couldn't find this answer here and I think it is the right one.
我在两年后回答这个问题,因为我在这里找不到这个答案,我认为这是正确的答案。