本着开源精神,任何Hibernate ORM问题都应该附上一个可复现的测试用例。这个测试用例证明了问题确实存在并且可以复现。

为了简化测试用例编写过程,Hibernate提供了一系列可以从GitHub获取的模板。多亏了这些测试,问题报告者可以专注于实际的持久化相关问题,因为模板负责所有启动逻辑。

之前,测试用例模板仅适用于Hibernate原生API,只要熟悉它就足够了。由于许多项目使用Hibernate作为JPA提供者,提供一个JPA启动环境也非常方便。这正是我们所做的。

接下来,我将提供一个编写基于JPA的Hibernate测试用例的逐步指南。

首先,您需要分叉或下载hibernate-test-case-templates GitHub仓库。

此仓库包含一个orm文件夹,包含两个Maven模块

hibernate-orm-4

用于复现Hibernate 4.x的问题

hibernate-orm-5

用于复现Hibernate 5.x的问题

每个模块有三个模板

ORMStandaloneTestCase.java

这是一个Hibernate原生测试用例(您可以访问SessionFactory并使用Session),但需要您手动启动Hibernate环境。

ORMUnitTestCase.java

这也是一个Hibernate原生测试用例(您可以访问SessionFactory并使用Session),但启动由您负责。

JPAUnitTestCase.java

这是一个新模板,用于使用Java持久化API复现问题(您可以访问EntityManagerFactory并使用EntityManager)。

在使用Hibernate本地API复制问题时,通常推荐使用ORMUnitTestCase

本文将重点介绍新添加的JPAUnitTestCase,其外观如下

public class JPAUnitTestCase {

    private EntityManagerFactory entityManagerFactory;

    @Before
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
    }

    @After
    public void destroy() {
        entityManagerFactory.close();
    }

    // Entities are auto-discovered, so just add them anywhere on class-path
    // Add your tests, using standard JUnit.
    @Test
    public void hhh123Test() throws Exception {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        // Do stuff...
        entityManager.getTransaction().commit();
        entityManager.close();
    }
}

在每个测试用例之前创建EntityManagerFactory,并在之后销毁它。测试用例逻辑位于@Test Junit方法内部。

您应将测试方法命名为您要复制的Hibernate JIRA问题。

EntityManagerFactory使用templatePU持久化单元,位于src/test/resources/META-INF/persistence.xml。默认情况下,此文件看起来像这样

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">

    <persistence-unit name="templatePU" transaction-type="RESOURCE_LOCAL">

        <description>Hibernate test case template Persistence Unit</description>
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <exclude-unlisted-classes>false</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.archive.autodetection" value="class, hbm"/>

            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1"/>
            <property name="hibernate.connection.username" value="sa"/>

            <property name="hibernate.connection.pool_size" value="5"/>

            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>

            <property name="hibernate.max_fetch_depth" value="5"/>

            <property name="hibernate.cache.region_prefix" value="hibernate.test"/>
            <property name="hibernate.cache.region.factory_class"
                      value="org.hibernate.testing.cache.CachingRegionFactory"/>

            <!--NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle-->
            <property name="hibernate.jdbc.batch_versioned_data" value="true"/>

            <property name="javax.persistence.validation.mode" value="NONE"/>
            <property name="hibernate.service.allow_crawling" value="false"/>
            <property name="hibernate.session.events.log" value="true"/>
        </properties>

    </persistence-unit>
</persistence>

persistence.xml配置文件已为启动Hibernate设置,提供了合理的默认环境。如果您想提供不同的配置,例如使用JTA与独立事务管理器,则必须更改默认配置。

所有实体都是自动发现的,因此您可以将它们放在类路径上的任何位置。在本例中,我们将使用以下实体

@Entity
public class Event {

    @Id
    @GeneratedValue
    private Long id;

    @Temporal(TemporalType.TIMESTAMP )
    private Date createdOn;

    public Event() {
    }

    public Event(Date createdOn) {
        this.createdOn = createdOn;
    }

    public Long getId() {
        return id;
    }

    public Date getCreatedOn() {
        return createdOn;
    }
}

现在,可以将持久化逻辑添加到JUnit测试方法中

@Test
public void hhh123Test() throws Exception {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    Event event = new Event( new Date() );
    entityManager.persist( event );

    Event dbEvent = entityManager.createQuery(
            "select e " +
            "from Event e", Event.class)
        .getSingleResult();
    assertEquals(event.getCreatedOn(), dbEvent.getCreatedOn());

    entityManager.getTransaction().commit();
    entityManager.close();
}

就这样!您现在可以使用标准的Java持久化API提供Hibernate测试用例。


返回顶部