2016-12-16 42 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嗎?你可以請張貼你的測試類註釋配置現在的樣子嗎? –