2016-12-16 81 views
0

我们的Spring Web应用程序的事务性JUnit测试失败。事务性SpringJUnit4测试失败

具体做法是:如果我单独执行与Maven每个测试它们贯穿:

mvn -Dtest=Test1 
mvn -Dtest=Test2 

如果我执行

mvn -Dtest=Test1,Test2 

我在一个测试中获得了JPA错误:

Could not open JPA EntityManager for transaction; nested exception is 
    java.lang.IllegalStateException: 
     Attempting to execute an operation on a closed EntityManagerFactory." 
     type="org.springframework.transaction.CannotCreateTransactionException" 
     org.springframework.transaction.CannotCreateTransactionException: 
      Could not open JPA EntityManager for transaction; nested exception is 
       java.lang.IllegalStateException: 
        Attempting to execute an operation on a closed EntityManagerFactory. 
         at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.verifyOpen(EntityManagerFactoryDelegate.java:338) 
         at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:303) 
         at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:336) 
         at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:302) 
         at org.springframework.orm.jpa.JpaTransactionManager.createEntityManagerForTransaction(JpaTransactionManager.java:449) 
         at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:369) 
         at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) 
         at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:439) 
         at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) 
         at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:64) 
         ... 

如果我设置surefire插件为每个测试重新创建整个JVM,他们也会遇到这种情况,这是一段疯狂的时间。

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-surefire-plugin</artifactId> 
    <version>${maven.surefire.version}</version> 
    <configuration> 
     <reuseForks>false</reuseForks> 
     <forkCount>1</forkCount> 
    </configuration> 
</plugin> 

应用设置:

  • 弹簧,用的Spring Roo
  • 的EclipseLink如JPA提供商

applicationContext.xml中用于测试设置(从而proxymode = asjectJ!):

<?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:context="http://www.springframework.org/schema/context" 
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" 
xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 
     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> 
<context:component-scan base-package="[packagename]"> 
    <context:exclude-filter expression=".*_Roo_.*" type="regex" /> 
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" /> 
</context:component-scan> 
<context:spring-configured /> 
<context:property-placeholder location="classpath*:META-INF/spring/*.properties" /> 
<context:annotation-config /> 

<bean class="org.springframework.orm.jpa.JpaTransactionManager" 
    id="transactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean> 

<tx:annotation-driven mode="aspectj" 
    transaction-manager="transactionManager" /> 

<bean 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
    id="entityManagerFactory"> 
    <property name="persistenceUnitName" value="persistenceUnit" /> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 
<bean class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close" id="dataSource"> 
    <property name="driverClassName" value="${test_database.driverClassName}" /> 
    <property name="url" value="${test_database.url}" /> 
    <property name="username" value="${test_database.username}" /> 
    <property name="password" value="${test_database.password}" /> 
    <property name="testOnBorrow" value="true" /> 
    <property name="testOnReturn" value="true" /> 
    <property name="testWhileIdle" value="true" /> 
    <property name="timeBetweenEvictionRunsMillis" value="1800000" /> 
    <property name="numTestsPerEvictionRun" value="3" /> 
    <property name="minEvictableIdleTimeMillis" value="1800000" /> 
    <property name="validationQuery" value="SELECT 1" /> 
</bean> 

<jdbc:initialize-database data-source="dataSource" 
    ignore-failures="ALL"> 
    <jdbc:script location="${test_database.selectLocation}" /> 
    <jdbc:script location="${test_database.initLocation}" /> 
    <jdbc:script location="${test_database.dataLocation}" /> 
</jdbc:initialize-database> 
</beans> 

JUnit测试看起来像:

@WebAppConfiguration 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { 
    "classpath:META-INF/spring/applicationContext.xml", 
    "classpath:META-INF/spring/webmvc-config.xml" }) 
@TransactionConfiguration(transactionManager = "transactionManager") 
@DirtiesContext 
public class Test1 { 

    @Autowired 
    WebApplicationContext wac; 

    private MockMvc mockMvc; 

    @PersistenceContext 
    EntityManager entityManager; 

    @Before 
    public void setup() throws Exception { 
     this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); 
    } 

    @Test 
    @Transactional 
    public void getJSONTest() throws Exception { 
    ... 
    } 
} 

没有任何人有任何想法,其中的两个测试是如何连接?一个人必须关闭其他entityManager,但为什么和如何?

任何想法感谢!

EDIT1:拟议中删除了@TransactionConfiguration和@DirtiesContext,但现在我得到一个

No transaction is currently active; nested exception is 
    javax.persistence.TransactionRequiredException 

EDIT2:我找到了这个问题至今该订单中,我执行测试戏剧一个洞。因此,测试不是彼此独立的。我尝试了几次注释和执行顺序的排列,每次产生不同的错误/行为。

眼下上一流水平的设置是:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { 
    "classpath:META-INF/spring/applicationContext.xml", 
    "classpath:META-INF/spring/webmvc-config.xml" }) 
@WebAppConfiguration 
@Transactional 
@DirtiesContext 

我再次把@DirtiesContext注释,因为新初始化的背景下,似乎有时帮助。

很难在这里追查真正的问题,但是我来到了一个具体问题:

我包我的测试类@Transactional,在我的测试方法我称之为

mockMvc.perform(MockMvcRequestBuilders.post(...)) 

,呼吁一个控制器方法。此控制器方法委托给另一个具有@Transactional方法的bean。在mockMvc.perform()返回后,我检查单元测试天气中的值是否写入数据库。我知道,只有在事务被提交给数据库或者使用相同的Transaction/entityManager的情况下,这才能工作。测试方法的交易是否与被叫控制器一样?还是我们在这里讨论两个不同的实体管理器/交易?

回答

0

我要说,@DirtiesContext正在做的是 - 在这里看到http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html

我想尝试:

  1. 删除@TransactionConfiguration(transactionManager的= “transactionManager的”) - 我相信这不是根据必要你的Spring XML配置
  2. 删除@DirtiesContext

然后再试试,如果情况好转... 这是我的设置用于测试DAO层(每个方法实际上到达真正的数据库,但由于@Rollback数据库从来没有被测试改变,因此测试不相互干扰)

@RunWith(SpringRunner.class) 
@ContextConfiguration(classes = RealDbDAOTests.class) 
@Transactional 
@Rollback 
public class DaoTests { 
.... 
} 
+0

对不起,“不接受“的答案,但我只注意到JPA错误消失了,但现在我有一个”异常说明:没有事务处于活动状态;“错误:/ – hFonti

+0

嗯,你有@Transactional annotatinon吗?你可以请张贴你的测试类注释配置现在的样子吗? –