2010-09-10 56 views
5

在單元測試之前,是否有一種最佳實踐模式,用於將數據庫完全重置爲使用JPA的新鋪好的模式?我一直在用hbml2ddl.auto = create-or-drop使用一個測試持久化單元,並在每次測試之前重新創建EMF,但我想知道是否有更簡單的方法來完成它。如何在每次測試之前重置JPA控制的數據庫?

+0

什麼是測試持久化單元?什麼是EMF?每次測試前你如何重現? – 2014-10-03 18:40:39

回答

1

單元測試不應該跟數據庫。

假設你正在爲你的數據訪問層編寫一個集成測試,你可以使用一個工具,如DBUnit,或者你可以創建一個靜態測試助手,通過使用JPA執行所有的刪除和插入,以編程方式重置數據庫狀態查詢內部的事務。

+1

你能證明你的初始斷言嗎? – HenryR 2010-09-10 05:44:42

+1

我想說的理由是'因爲數據庫很慢'。當使用Oracle等等,甚至打開一個連接很慢時,這是真的。內存數據庫不是這樣。 – 2010-09-10 06:00:22

+8

我想說的理由是「單元」測試應該單獨測試「單元」。一旦涉及數據庫,您就不會進行單元測試,而是進行集成測試。它與使用的數據庫類型無關。 – 2010-09-10 06:49:54

1

重置數據庫,如果你使用一個快速的Java數據庫,如H2 database或HSQLDB是不是一個大問題。與使用Oracle/MySQL(或任何用於生產的任何產品)相比,這將加快您的測試速度,並確保所有代碼都在使用「真實」生產數據庫時進行測試。

爲了獲得最大的性能,可以在內存中使用H2(這樣你可以不必手動重置數據庫 - 如果連接被關閉,它會自動重置),也可以使用普通持久的數據庫。要在H2中使用後重置數據庫,請運行(native)語句「刪除所有對象刪除文件」。

+0

你如何強制連接關閉? – 2014-10-02 20:36:36

0

是否有一個最佳實踐模式,用於在單元測試之前使用JPA將數據庫完全重置爲新鋪好的模式?

不要在每個單元測試之前重置整個數據庫模式,而是在每個單元測試的結束時重置「數據庫環境(特定於當前單元測試)」。

我們有一個實體...

@Entity 
public class Candidate implements { 
    private String id; 
    private String userName; 
    private EntityLifeCycle lifeCycle; 

    protected Candidate() { 
    } 
    public Candidate(String userName) { 
     this.userName = userName; 
    } 

    @Id @GeneratedValue(generator="uuid", strategy=GenerationType.AUTO) 
    @GenericGenerator(name="uuid", strategy="uuid", parameters = {}) 
    @Column(name="candidate_id", nullable=false, unique=true) 
    public String getId() { 
     return id; 
    } 
    protected void setId(String id) { 
     this.id = id; 
    } 

    @Column(name="user_name", nullable=false, unique=true) 
    public String getUserName() { 
     return userName; 
    } 
    public void setUserName(String userName) { 
     this.userName = userName; 
    } 

    @Embedded 
    public EntityLifeCycle getLifeCycle() { 
     if(lifeCycle == null) { 
      lifeCycle = new EntityLifeCycleImpl(); 
     } 
     return lifeCycle; 
    } 
    public void setLifeCycle(EntityLifeCycleImpl lifeCycle) { 
     this.lifeCycle = lifeCycle; 
    } 

    @PrePersist 
    public void prePersist() { 
     lifeCycle.setCreatedDate(new Date()); 
    } 
} 

我們正在爲在prePersist(每個候選實例)方法createdDate。這裏是斷言createdDate是越來越正確設置一個測試用例....

public class EntityLifeCycleTest { 
    @Test 
    public void testLifeCycle() { 
     EntityManager manager = entityManagerFactory.createEntityManager(); 
     Candidate bond = new Candidate("Miss. Bond"); 
     EntityTransaction tx = manager.getTransaction(); 
     tx.begin(); 
     manager.persist(bond); 
     tx.commit(); 

     Assert.assertNotNull(bond.getLifeCycle().getCreatedDate()); 
     manager.close(); 
    } 
} 

這個測試用例將首次運行正常。但是如果我們第二次運行這個測試用例,它會拋出ConstraintViolationException,因爲userName是唯一鍵。

因此,我認爲正確的做法是在每個測試用例的末尾「清理數據庫環境(特定於當前單元測試)」。像這樣...

public class EntityLifeCycleTest extends JavaPersistenceTest { 
    @Test 
    public void testLifeCycle() { 
     EntityManager manager = entityManagerFactory.createEntityManager(); 
     Candidate bond = new Candidate("Miss. Bond"); 
     EntityTransaction tx = manager.getTransaction(); 
     tx.begin(); 
     manager.persist(bond); 
     tx.commit(); 

     Assert.assertNotNull(bond.getLifeCycle().getCreatedDate()); 

     /* delete Candidate bond, so next time we can run this test case successfully*/ 
     tx = manager.getTransaction(); 
     tx.begin(); 
     manager.remove(bond); 
     tx.commit(); 
     manager.close(); 
    } 
} 

我一直在使用一個測試持久單元與hbml2ddl.auto =創建-或降每次測試前和重建電磁場,但我不知道是否有一個更清潔的方式來做到這一點。

在每次測試之前重新創建EMF耗時,IMO。

只有在對影響底層數據庫的@Entity註釋類進行了一些更改(例如添加/刪除列和/或約束)時,才刪除並重新創建數據庫模式。因此,首先驗證架構,如果架構有效,則不要重新創建它,如果無效,則重新創建它。喜歡這個...現在

public class JavaPersistenceTest { 
    protected static EntityManagerFactory entityManagerFactory; 
@BeforeClass 
public static void setUp() throws Exception { 
    if(entityManagerFactory == null) { 
     Map<String, String> properties = new HashMap<String, String>(1); 
     try { 
      properties.put("hibernate.hbm2ddl.auto", "validate"); 
      entityManagerFactory = Persistence.createEntityManagerFactory("default", properties); 
    } catch (PersistenceException e) { 
     e.printStackTrace(); 
     properties.put("hibernate.hbm2ddl.auto", "create"); 
     entityManagerFactory = Persistence.createEntityManagerFactory("default", properties); 
    } 
     } 
} 
} 

,如果你運行所有的測試用例一氣呵成(擴展JavaPersistenceTest)時,EMF將創建只有一次(或兩次,如果模式無效)。

+2

我不同意,[良好的設置不需要清理!](http://www.dbunit.org/bestpractices.html#nocleanup) – 2010-09-10 06:47:15

+0

@PascalThivent它並不總是如此。如果有例如一個findAll()方法的測試,我想確保數據庫中沒有比我預期更多的記錄,那麼是的,我希望在測試之前清理所有其他記錄。即使這個數據庫是我的,我想保持清楚,因爲它是必要的。 – 2012-03-17 17:38:16

相關問題