java - 使用 Hibernate/JPA 映射和 JUnit 测试 DAO 的公式

标签 java hibernate jpa junit tdd

我发现了很多与此相关的问题,但很多讨论都是围绕使用 HSQL 数据库而不是配置 Eclipse 和命令行来运行实际测试。

假设我有以下虚构的场景:

@Entity
@Table("Team")
public class Team {
    private Integer id;
    private String name;
    private String city;
    private String owner;
    private List<Player> players;

    @Column(name="TEAM_ID")
    public Integer getTeamId() {
       return this.id;
    }

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

    @Column(name="TEAM_ID")
    public Integer getName() {
       return this.name;
    }

    public void setName(String name) {
       this.name = name;
    }

    // ... etc.
}

假设我们有以下数据访问层:

@Repository
public class TeamDao {

    @PersistenceContext(unitName="examplePU")
    EntityManger em;

    public Team saveOrUpdate(Team team) {
        this.em.merge(team);
    }

    // etc...
}

我希望能够编写类似于以下内容的集成测试:

public class TeamIntegrationTest {

    @Resource
    TeamDao teamDao;

    @Test
    public void resourceLoaded() {
        assertNotNull(teamDao);
    }

    @Test
    public void testInsertTeam() {
        Team team = new Team();
        team.setName("Packers");
        team.setCity("Green Bay");
        teamDao.saveOrUpdate(team);
    }
}

在提交以确保它正常工作之前,在我自己的开发环境中运行它需要什么?请包括对可能有帮助的相关库的引用。

最后,我想创建一个可以用于 future 项目的公式(我也相信这是许多其他企业开发人员的目标)。


提议的公式

与其将此作为解决方案输入并提名自己作为提供答案的人,我觉得最好标记与我正在寻找的内容最接近的答案并对其进行扩展。配置是一种痛苦,这正是我希望通过提出这个问题来获得知识的原因。最后,我选择了依靠 Spring 来帮我们处理一堆烦人的事情。

首先,配置(假设src/{main,test,inttest}/java, src/{main,test,inttest}/resources设置:

src/resources/java
|
| - META-INF
|    |
|    | - orm.xml
|    | - persistence.xml
| - applicationContext.xml
| - applicationContext-Integration.xml

orm.xml 内容不多,但是没有的时候我遇到了问题:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
          http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
</entity-mappings>

Persistence.xml 包含 JPA 应该知道的实体:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="persistenceUnitName">
        <class>com.acme.project.className</class>
        <!-- Etc... -->
    </persistence-unit>
</persistence>

applicationContext.xml 包含大部分配置:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring configuration for JPA/database/Transactions -->
<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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:annotation-config/>

    <context:component-scan base-package="com.acme.project.full.package.name" />

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

    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entityManagerFactory-ref="entityManagerFactory" p:dataSource-ref="jndiDataSource"
        p:jpaDialect-ref="jpaDialect" />

    <bean id="jndiDataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.databaseType.jdbc.Driver" />
            <property name="url" value="jdbc:url://location:port/databaseName" />
            <property name="username" value="" />
            <property name="password" value="" />
    </bean>

    <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        lazy-init="true" p:dataSource-ref="jndiDataSource"
        p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter"
        p:persistenceUnitName="persistenceUnitName" p:jpaDialect-ref="jpaDialect">
    </bean>

    <bean id="hibernateJpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
        p:databasePlatform="org.hibernate.dialect.MySQLDialect" p:generateDdl="false"
        p:showSql="true" />

我们正在使用 EntityManager,因此推荐的解决方案 AbstractTransactionalDataSourceSpringContextTests不会为我们工作。相反,我们创建了以下内容以引入 SpringJUnit4ClassRunner.class 并正确设置 applicationContext。

@ContextConfiguration(locations = { "classpath:applicationContext-JPA-Integration.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class SpringBasedIntegration { }

我们创建了这个通用类,以便它可以跨其他集成测试类使用,

public class TeamIntegrationTest extends SpringBasedIntegration {

    @Resource
    TeamDao vitalDao;

    @Before() 
    public void before() {
        List<Team> teams = teamDao.getKnownValues("...");
        for(Team entry : teams) {
            vitalDao.deleteTeam(team);
        }
    }

    @Test
    public void testSomething() { 
        // vitalDao should be initialized with an entityManger!
    }

现在,这有一个不能回滚数据的弱点,所以我引入了一个 hack,它将使用 @Before 方法删除已知值,以便每个方法都有一个新的已知状态。这可能适用于某些人,但可能不适用于所有人。

欢迎所有反馈。我希望社区拥有用于集成测试 JPA/Hibernate 的记录完备的解决方案,我们都知道 StackOverflow 是 Google 上我们查询的最佳第一结果。

最佳答案

尝试一下 Spring 框架,

您可以对 JUNIT 类使用 Spring Transactional Test;它运行测试,但在操作完成后回滚每个更改。您可以将此行为更改为实际提交,这取决于您。

神奇的是一个名为 AbstractTransactionalDataSourceSpringContextTests 的类,在您的情况下,您需要在本地项目中设置一个 applicationcontext 并使用 eclipse junit runner 运行测试。

这是一个使用 AbstractTransactionalDataSourceSpringContextTests 的好教程 http://zenoconsulting.wikidot.com/blog:8

其他链接 http://www.infoq.com/articles/testing-in-spring http://static.springsource.org/spring/docs/2.5.x/reference/testing.html#testcontext-support-classes-junit44

关于java - 使用 Hibernate/JPA 映射和 JUnit 测试 DAO 的公式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8546521/

相关文章:

Java,用Runtime.exec()继承类路径

java - 如何同步多个线程写入文件

java - 只是获取 id 列值而不是在 hibernate 对象中使用 join 一对多关系

java - Hibernate:无法删除对象 - 外键约束 - CascadeType.REMOVE

java - 我的JPA查询方法是否正确?

java - 进度条完成时调用方法

java - 在 JTextPane 中绘制水平线

java - Bean 在 Spring 4.2.5 的 ContextRefreshedEvent 上没有事务代理

java - 如何使字段成为 BLOB 而不是 TINYBLOB?

mysql - Glassfish 4 身份验证(JDBCRealm 和 JPA 2)适用于 Dery,但不适用于 MySQL