当前位置: 首页 > 知识库问答 >
问题:

Transactional SpringJUnit4测试失败

朱俭
2023-03-14

SpringWeb应用程序的事务JUnit测试失败。

具体地说:如果我分别使用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,与Spring Roo(因此proxyMode=asjectJ!)
  • Eclipselink作为JPA提供商

应用程序上下文。用于测试设置的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: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 {
    ...
    }
}

有人知道其中两个测试是如何联系在一起的吗?一个必须为另一个关闭实体管理器,但是为什么以及如何关闭呢?

任何想法都值得赞赏!

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(...))

,调用控制器方法。此控制器方法委托给另一个bean,该bean具有@Transactional方法。在模拟MVC之后。perform()返回,我正在检查单元测试中的值是否已写入数据库。我知道,只有当事务提交到数据库,或者使用相同的事务/entityManager时,这才能起作用。测试方法的事务是否与被调用控制器的事务相同,或者我们在这里讨论的是两个不同的EntityManager/事务?

共有1个答案

尉迟俊能
2023-03-14

我想说@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 {
 ....
}
 类似资料:
  • 我有一些mocha/chai/chai-http测试,它们遵循下面的结构,但是,每当一个测试失败时,我会得到一个 ,我似乎不知道它的来源。 UnhandledPromiserEjectionWarning:未处理的承诺拒绝。此错误可能是由于不带catch块的异步函数内部引发的,或者是由于拒绝了未用。catch()处理的承诺。 我尝试在 后面添加一个 承诺.reject(err)/code>,但也不

  • 我正在尝试从spring启动应用程序中的服务执行JUnit4测试,并且我一直使用init获取entityManagerFactory。 我还希望使用我的应用程序连接。属性文件,但它希望使用嵌入式hsqldb进行连接。 有人能给我指出正确的方向吗? 以下是相关代码: 应用特性: 主要内容: 实体: DAO/存储库: 服务: 测试: 本应包括以下内容: 堆叠:

  • 问题内容: 我正在使用hamcrest 1.3测试我的代码。这简直是​​死。我试图对其进行测试,以确保生成的数字小于13。我有一条打印语句,其中打印了生成的数字。生成的数字始终小于13,但测试始终失败。我做错什么了吗? 这是我正在测试的代码。 这是我的测试代码。 编辑:这是故障堆栈跟踪。 问题答案: 这是帮助我解决问题的站点。 http://code.google.com/p/hamcrest/i

  • 我有一个简单的测试用例: FileManager中的函数删除 /myDir下的所有文件,然后再次保留文件。 如上所述,我有一个。运行时,我可以按以下顺序查看所有打印: 但是,测试在失败。有两件事我不明白: > 我不明白,它在中失败了,为什么我仍然可以看到打印的,听起来就像是失败了,它没有停止运行,而是继续运行下一个测试?JUnit测试用例中的场景背后发生了什么?? 我不明白的另一件事是为什么tes

  • 因为我们的测试环境不使用HTTPS,所以我们对Android 9的UI测试失败了。问题是,我们正在从espresso测试中进行网络调用(例如,直接在后端创建全新的用户以用于测试),这意味着它们在espresso测试应用程序上运行。 将networkSecurityConfig添加到应用程序清单无济于事,因为问题不在于应用程序,而在于espresso应用程序。 我怎么才能修好这个?espresso应