Весенние тесты - проблемы с откатом - PullRequest
4 голосов
/ 03 января 2012

Я создал тест интеграции Spring в своем приложении. Проблема в том, что один тест не выполняет откат должным образом, оставляет некоторые данные в базе данных и приводит к сбою последующих тестов.

Я заметил, что тесты работают хорошо, если постоянная сущность является простой сущностью. Тест не пройден, когда сущность является частью иерархии наследования, а тип наследования имеет тип InheritanceType.JOINED. Когда я изменяю это на InheritanceType.SINGLE_TABLE, это не терпит неудачу.

Ниже приведен код: Тестовый класс:

 @RunWith(SpringJUnit4ClassRunner.class)
 @Transactional
 @ContextConfiguration(locations = {"classpath:beans/repository-beans.xml"})
 public class OnlyParentRollbackProblemSpringTest {
@PersistenceContext
private EntityManager entityManager;

@Test
//PASSES
public void isDBEmptyTest_1() throws Exception {
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi");
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue();
    assertThat(elementsCount).isEqualTo(0);
}

@Test
//PASSES
public void testThatInfluencesOtherTests() {
    ParentEntity queueItem = new ParentEntity();
    entityManager.persist(queueItem);
    ParentEntity queueItem1 = new ParentEntity();
    entityManager.persist(queueItem1);
    // given
    flush();
    // when
    Query deleteQuery = entityManager.createQuery("delete from " + ParentEntity.class.getSimpleName());
    deleteQuery.executeUpdate();
    flush();
    // then
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi");
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue();
    assertThat(elementsCount).isEqualTo(0);
}

@Test
//FAILS
public void isDBEmptyTest_2() throws Exception {
    Query countQuery = entityManager.createQuery("select count(qi) from " + ParentEntity.class.getSimpleName() + " qi");
    int elementsCount = ((Long)countQuery.getSingleResult()).intValue();
    assertThat(elementsCount).isEqualTo(0);
}

private void flush() {
    entityManager.flush();
    entityManager.clear();
}
 } 

конфигурация пружины:

<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">


<context:component-scan base-package="no.mintra.offlinetrainingportal.infrastructure.persistence" />

<bean
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

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

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


<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
    <property name="dataSource" ref="H2DataSource" />
    <property name="jpaVendorAdapter" ref="H2JpaVendorAdaptor" />
    <property name="jpaPropertyMap">
        <map>
            <entry key="hibernate.hbm2ddl.auto" value="create-drop" />
        </map>
    </property>
</bean>

<bean id="H2DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MYSQL;LOCK_MODE=3"/>
</bean>

<bean id="H2JpaVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
    <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
</bean>

Объекты:

@javax.persistence.Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ParentEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

public ParentEntity() {
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}
} 

@Entity
public class SecondChildEntity extends ParentEntity {
@Column(unique = true)
@NotNull
private Integer userId;

public SecondChildEntity(Integer userId) {
    this.userId = userId;
}

public Integer getUserId() {
    return userId;
}
}

И файл pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>test</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>test</name>
<url>http://maven.apache.org</url>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit.version>4.8.1</junit.version>
    <org.springframework.version>3.1.0.RELEASE</org.springframework.version>
    <log4j.version>1.2.15</log4j.version>
    <org.slf4j.version>1.5.8</org.slf4j.version>
    <hibernate-core.version>3.6.8.Final</hibernate-core.version>
    <hibernate-validator.version>4.1.0.Final</hibernate-validator.version>
    <commons-dbcp.version>1.2.2</commons-dbcp.version>
    <h2database.version>1.3.163</h2database.version>
    <commons-collections.version>3.2.1</commons-collections.version>
    <javax.servlet.version>2.5</javax.servlet.version>
    <javax.validation.version>1.0.0.GA</javax.validation.version>
    <fest.version>1.2</fest.version>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <encoding>UTF-8</encoding>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>${h2database.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.easytesting</groupId>
        <artifactId>fest-assert</artifactId>
        <version>${fest.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
        <exclusions>
            <exclusion>
                <groupId>com.sun.jmx</groupId>
                <artifactId>jmxri</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${org.slf4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${org.slf4j.version}</version>
    </dependency>


    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>${hibernate-validator.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${org.springframework.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.hibernate</groupId>
                <artifactId>ejb3-persistence</artifactId>
            </exclusion>
        </exclusions>
        <version>${hibernate-core.version}</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate-core.version}</version>
    </dependency>

</dependencies>

1 Ответ

3 голосов
/ 03 января 2012

Эта проблема относится только к СУБД H2.

H2Dialect содержит следующее предупреждение:

if ( !( majorVersion > 1 || minorVersion > 2 || buildId >= 139 ) ) {
    log.warn(
        "The {} version of H2 implements temporary table creation such that it commits " +
        "current transaction; multi-table, bulk hql/jpaql will not work properly",
        ( majorVersion + "." + minorVersion + "." + buildId )
    );
}

Вы сталкиваетесь с этой проблемой, поскольку выполнение массового delete для объекта с наследованием JOINED включает создание временной таблицы (см. Сгенерированный SQL), так что первая часть транзакции будет зафиксирована.

В качестве обходного пути вы можете использовать собственные запросы SQL вместо массового запроса HQL delete.Или просто используйте другую базу данных в памяти, такую ​​как HSQLDB.

...