0

我正在尝试为我的持久性代码创建一个单元测试。我正在使用带有 JPA 注释的 Hibernate。我没有persistence.xml(在所有关于JPA 单元测试的文章中都使用了它)。我不想使用spring或创建persistence.xml,因为我有很多持久性类,并且所有这些类的hibernate初始化都需要很多时间,所以我想显式地将类添加到hibernate。

我也不能configuration.createSessionFactory()像在 Hibernate 单元测试文章中推荐的那样使用它,因为我的 DAO 有 Spring 注入的 JPA EntityManager。

所以我正在使用EntityManagerFactoryImpl

AnnotationConfiguration configuration = new AnnotationConfiguration();

configuration.setProperty(Environment.DRIVER,"org.apache.derby.jdbc.EmbeddedDriver");
configuration.setProperty(Environment.URL,"jdbc:derby:memory:srf.derby;create=true");
configuration.setProperty(Environment.USER, "");
configuration.setProperty(Environment.DIALECT, DerbyDialect.class.getName());
configuration.setProperty(Environment.SHOW_SQL, "true");
configuration.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
configuration.setProperty( Environment.AUTOCOMMIT, "true");

configuration.addAnnotatedClass(MyPersistentClass.class);

MyHibernateDAO dao = new MyHibernateDAO();

EntityManagerFactoryImpl entityManagerFactory = new EntityManagerFactoryImpl(
                                  configuration.buildSessionFactory(),
                                  PersistenceUnitTransactionType.RESOURCE_LOCAL, 
                                  true, 
                                  null, 
                                  configuration);

dao.setEntityManager(entityManagerFactory.createEntityManager());

这看起来不错,但由于某种原因,没有任何插入触发到 db,而所有选择都可以(我已经显示 SQL 为真)。看起来 AUTOCOMMIT 是错误的(在生产环境中,Spring 管理事务)。如您所见,我将配置设置为 AUTOCOMMIT true,我什至从 EntityManager 检索 JDBC 连接,并且在调试器中看到,自动提交为 true,但只有在我的单元测试中我明确开始并提交事务时才会触发插入。

我做错了什么?如何让我的测试在自动提交中运行?

谢谢!

4

1 回答 1

0

我假设您在 DAO 代码中使用 @Transactional-annotations。问题是,当您手动实例化 EntityManager 和 DAO 时,没有 TransactionManager 或代理来处理对这些注释的反应,因此永远不会自动创建事务。

如果您真的想在测试中将数据提交到数据库而不创建 Spring ApplicationContext 或不使用 Springs 的 JUnit-runners 等,我相信您需要自己处理事务(虽然可能是错误的)。最简单的方法可能是创建一个基类来扩展您的测试,例如:

import javax.persistence.EntityManager;

import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

public abstract class TransactionalTestBase
{
    private EntityManager em;

    protected abstract Class<?>[] getAnnotatedClasses();

    @BeforeClass
    public void setupEntityManager()
    {
        //Build your basic configuration

        AnnotationConfiguration configuration = new AnnotationConfiguration();
        //configuration.setProperty(
        //...

        //Ask the implementing class for the entity-classes
        for(Class<?> clazz : getAnnotatedClasses())
        {
            configuration.addAnnotatedClass(clazz);
        }

        //Set up your entitymanager here

    }

    @Before
    public void beforeTest()
    {
        em.getTransaction().begin();
    }

    @After
    public void afterTest()
    {
        if(em.getTransaction().getRollbackOnly())
        {
            em.getTransaction().rollback();
        }
        else
        {
            em.getTransaction().commit();
        }
    }

    @AfterClass
    public void tearDownEntityManager()
    {
        em.flush();
        em.clear();
        em.close();
        em = null;
    }
}

请注意,当您从中扩展更多类时,您可以添加更多@BeforeClass、@Before 等-注释,它们将按继承顺序运行。

如果您决定在测试中使用 Spring,请参阅http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html

于 2012-01-29T09:45:48.973 回答