2012-05-28 251 views
5

我有一個使用JUnit做一些測試套件的生命週期問題。JUnit生命週期

爲了寫得心應手JPA 2.0單元測試 作爲一個Java開發 我想:

  • 所有測試套件前一次初始化一個EntityManagerFactory實例。我使用@BeforeClass註釋
  • 實例化一個EntityManager實例和每個測試用例之前啓動一個新的事務,並回滾之前像AOP的開始交易達成目的/後或around通知
  • 能夠讓任何設置/在任何衍生測試套件之前/之後的拆卸操作

我一直在編寫JUnit測試。但在這種情況下,我對列表中的第二項和第三項產生了問題。

請看看下面的測試套件的例子:

抽象測試套件

public abstract class AbstractPersistenceTest { 

    protected static EntityManagerFactory emf; 
    protected EntityManager em; 

    @BeforeClass 
    public static void setUpClass() { 
     emf = Persistence.createEntityManagerFactory("test"); 
    } 

    @Before 
    public void setUp() { 
     em = emf.createEntityManager(); 
     em.getTransaction().begin(); 
    } 

    @After 
    public void tearDown() { 
     em.getTransaction().rollback(); 
     em.close(); 
    } 

    @AfterClass 
    public static void tearDownClass() { 
     emf.close(); 
    } 

} 

派生測試套件

public class EmployeeJpqlTest extends AbstractPersistenceTest { 

    private Employee john; 
    private Employee jack; 

    @Before 
    public void setUp() { 
     john = new Employee("John Doe", 1000); 
     jack = new Employee("Jack Line", 1010); 

     em.persist(john); 
     em.persist(jack); 
    } 

    @Test 
    public void itShouldRetrieveAllEmplloyees() { 
     TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e", 
       Employee.class); 
     List<Employee> employees = query.getResultList(); 

     assertArrayEquals(new Employee[] { john, jack }, employees.toArray()); 
    } 

    @Test 
    public void itShoulRetrieveAllEmployeeNames() { 
     TypedQuery<String> query = em.createQuery(
       "SELECT e.name FROM Employee e", String.class); 
     List<String> names = query.getResultList(); 

     assertArrayEquals(new String[] { john.getName(), jack.getName() }, 
       names.toArray()); 
    } 

} 

由於不確定的JUnit生命週期註釋的順序NullPointerException在th中佔據一席之地e派生類中的setUp()方法。對我來說很清楚。

有沒有可能在沒有在任何派生測試套件類的每個setUp()/ tearDown()方法中手動注入啓動/回滾事務代碼的情況下獲得目標? 或者,也許有沒有其他的JUnit平均或測試框架可以提供一種簡單的方式來表達我的需求?

在此先感謝。

回答

2

您如何使用Google Guice將實體管理器和事務注入您的測試方法?

import com.google.inject.persist.Transactional; 
import javax.persistence.EntityManager; 

public class MyTest { 
     @Inject EntityManager em; 

     @Test 
     @Transactional 
     public void createNewPerson() { 
       em.persist(new Person(...)); 
     } 
} 

它可以簡化這方面的大量工作。

+0

是的,這是個好主意。由於Google Guice是一款精益IoC,因此可以在不受代碼影響的情況下使用。 –

1

爲什麼不在setUp,super.setUpClass等電話super.setUp()?你實際上在做的是重寫子類的方法。

+0

其實我是這樣做的,因此在測試運行期間,父行器的'setUp()'方法在一行中被調用兩次 - 直接從我的代碼執行一次,第二次由JUnit執行與JUnit生命週期相關的操作。 –

1

考慮使用Spring處理非靜態實體管理器和事務回滾的一次性實例化。即使你沒有在你的應用程序中使用Spring,你也可以在測試中使用它。詳情請參閱http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/testing.html的第9.3節。

+0

是的,我完全同意你的看法。這是一個非常方便的選擇。這個特別的項目非常小巧,所以我避免使用Spring,理解我拒絕的東西。謝謝。 –