Hibernate的单元测试中没有自动提交JPA注释

Hibernate的单元测试中没有自动提交JPA注释,hibernate,unit-testing,jpa,junit,autocommit,Hibernate,Unit Testing,Jpa,Junit,Autocommit,我正在尝试为我的持久性代码创建一个单元测试。 我正在使用Hibernate和JPA注释。我没有persistence.xml(所有关于JPA单元测试的文章都使用它)。 我不想使用spring或创建persistence.xml,因为我有很多持久性类,而hibernate的初始化需要很多时间,所以我想显式地向hibernate添加类 此外,我不能像在Hibernate单元测试文章中推荐的那样使用configuration.createSessionFactory(),因为我的DAOs中有Sprin

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

此外,我不能像在Hibernate单元测试文章中推荐的那样使用
configuration.createSessionFactory()
,因为我的DAOs中有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 true)。看起来AUTOCOMMIT为false(在生产环境中,Spring管理事务)。正如您所看到的,我将配置设置为AUTOCOMMIT true,甚至从EntityManager检索JDBC连接,并在调试器中看到AUTOCOMMIT为true,但只有在单元测试中我显式开始并提交事务时才会触发插入

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


谢谢大家!

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


如果您确实希望在测试中向数据库提交数据,而不创建Spring应用程序上下文或不使用Spring的JUnit运行程序等,我相信您需要自己处理事务(尽管可能是错误的)。最简单的方法可能是创建一个基类,从中扩展测试,例如:

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;
    }
}
import javax.persistence.EntityManager;
导入org.hibernate.cfg.AnnotationConfiguration;
导入org.junit.After;
导入org.junit.AfterClass;
导入org.junit.Before;
导入org.junit.BeforeClass;
公共抽象类TransactionalTestBase
{
私人实体管理者;
受保护的抽象类[]GetAnnotatedClass();
@课前
public void setupEntityManager()
{
//构建您的基本配置
AnnotationConfiguration=新的AnnotationConfiguration();
//configuration.setProperty(
//...
//向实现类询问实体类
for(类clazz:getAnnotatedClass())
{
配置.addAnnotatedClass(clazz);
}
//在这里设置您的entitymanager
}
@以前
测试前公共无效()
{
em.getTransaction().begin();
}
@之后
公开无效后验()
{
if(em.getTransaction().getRollbackOnly())
{
em.getTransaction().rollback();
}
其他的
{
em.getTransaction().commit();
}
}
@下课
public void tearDownEntityManager()
{
em.flush();
em.clear();
em.close();
em=null;
}
}
注意,当您从此扩展更多的类时,您可以添加更多的@BeforeClass、@Before等注释,它们将按继承顺序运行


如果您决定在测试中利用Spring,请参见

是,我正在使用注释。我是否可以通过某种方式配置EntityManager,以便在每次插入和更新后进行提交?您建议如何对此类代码进行单元测试?如果您真的希望在测试中提交数据到数据库,而无需创建Spring应用程序上下文或使用Springs的JUnit Runner等,我相信您需要自己处理事务(尽管可能是错误的)。此外,单元测试不应该依赖外部资源(如数据库),但使用mock代替,集成测试是另一回事。如果您决定利用Spring进行测试,请参见“谢谢”。但是,我们希望使用内存数据库测试我们的DB代码。我们目前使用Spring进行此类测试,但为所有类初始化Hibernate(即使是内存中的DB)需要花费太多时间。这些“单元”测试需要几分钟。我在探查器中检查了大部分时间都花在Hibernate运行的反射上,所以我只想在Hibernate管理的每个测试中创建几个类。你知道使用Spring的方法吗?我是这样做的,我尝试在@Before中打开事务的,但是在我这样做之后,我的“选择”似乎然后看不到“插入”的结果。谢谢!请注意,对于我回答中的基类,在测试方法退出之前,事务不会提交到数据库,因此,如果您在同一测试方法中插入数据,然后尝试读取它,它可能不会显示,因为它尚未提交。但是,您可以在测试过程中调用
postest
,以提交事务,例如出于某些目的,您可能希望将该方法重命名为类似于
commit