2012-01-29 28 views
0

我試圖爲我的持久性代碼創建一個單元測試。 我使用Hibernate和JPA註釋。我沒有persistence.xml(在所有關於JPA單元測試的文章中都使用過)。 我不想使用spring或者創建persistence.xml,因爲我有很多持久化類,並且所有的持久化類的初始化都需要花費很多時間,所以我想明確地爲hibernate添加類。沒有AUTO COMMIT在休眠單元測試JPA批註

另外我不能使用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()); 

這看起來不錯,但因爲某種原因沒有任何插入被炒到數據庫,而所有的選擇都好(我有顯示SQL真)。它看起來像AUTOCOMMIT是錯誤的(在生產世界中,Spring管理事務)。正如你所看到的,我將配置設置爲AUTOCOMMIT true,我甚至從EntityManager中檢索JDBC連接,並在調試器中看到autocommit爲true,但只有在我的單元測試中明確地開始和提交事務時纔會觸發插入。

我在做什麼錯了?我如何使我的測試在自動提交中運行?

謝謝!

回答

0

我假設你在你的DAO代碼中使用@ Transactional-annotations。問題是,當你手動實例化你的EntityManager和DAO時,沒有TransactionManager或代理負責對這些註釋做出反應,所以事務從不會自動創建。

如果你真的想在沒有創建Spring ApplicationContext或沒有使用Springs的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; 
    } 
} 

注意,當你從這個進一步延伸類,你可以添加更多的@BeforeClass,@Before等-annotations,他們將按繼承順序運行。

如果你決定利用與您的測試春天,看到http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html

+0

是的,我使用的註解。我可以以某種方式配置我的EntityManager在每次插入和更新後進行提交嗎? 你會如何推薦單元測試這樣的代碼? – 2012-01-29 10:19:27

+0

如果你真的想在測試中向數據庫提交數據而不創建Spring ApplicationContext或者沒有使用Springs的JUnit運行器等,我相信你需要自己處理事務(儘管可能是錯誤的)。此外,單元測試不應該依賴外部資源(比如數據庫),但是使用mock代替,集成測試是另一回事。如果您決定在測試中使用Spring,請參閱http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html – esaj 2012-01-29 10:29:55

+0

謝謝!但是我們想要使用內存數據庫來測試我們的DB代碼。我們目前使用spring進行這樣的測試,但是對於我們所有的類來說,初始化Hibernate(甚至是內存數據庫)需要很長時間。這些「單元」測試需要幾分鐘。我檢查了剖析器,大部分時間都花在由Hibernate運行的反射上,所以我只想在Hibernate管理的每個測試中只做幾個類。你知道一種使用Spring的方法嗎? – 2012-01-29 10:35:50