使用RunWith註解改變JUnit的預設執行類,並實現自已的Listener在平時的單元測試,如果不使用RunWith註解,那麼JUnit將會採用預設的執行類Suite執行,如下類:
public class TestClass {@Test public void t1(){}}
JUnit允許使用者指定其它的單元測試執行類,只需要我們的測試執行類繼承類org.junit.runners.BlockJUnit4ClassRunner就可以了,Spring的執行類SpringJUnit4ClassRunner就是繼承了該類。我們平時用Spring也比較多,為了能夠更加方便的引用設定檔,我們單元測試就使用了Spring實現的執行類。此時的單元測試執行類將會看起來是這樣:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { "classpath*:/spring1.xml", "classpath*:/spring2.xml" })@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class })@Transactionalpublic class TestClass {@Inject//這個類會在執行時被注入,這裡是按類型注入,如果想按名稱注入,需要加上@Named註解,如@Named("class1")//實作類別可以加上@Named("class1")註解,也可以是配置在設定檔中的Class1 class1;@Test public void t1(){}}
以下分別對使用到的幾個註解進行解釋:
@RunWith:這個是指定使用的單元測試執行類,這裡就指定的是SpringJUnit4ClassRunner.class;
@ContextConfiguration:這個指定Spring設定檔所在的路徑,可以同時指定多個檔案;
@TestExecutionListeners:這個用於指定在測試類別執行之前,可以做的一些動作,如這裡的DependencyInjectionTestExecutionListener.class,就可以對一測試類別中的依賴進行注入,TransactionalTestExecutionListener.class用於對事務進行管理;這兩個都是Srping內建的; 我們也可以實現自己的Listener類來完成我們自己的操作,只需要繼續類org.springframework.test.context.support.AbstractTestExecutionListener就可以了,具體可以參照DependencyInjectionTestExecutionListener.class的實現,後面我會貼出執行個體。
Listener實在實作類別執行之前被執行、實作類別的測試方法之前被執行,這與Listener的實現有關。
@Transactional:這裡的@Transactional不是必須的,這裡是和@TestExecutionListeners中的TransactionalTestExecutionListener.class配合使用,用於保證插入的資料庫中的測試資料,在測試完後,交易回復,將插入的資料給刪除掉,保證資料庫的乾淨。如果沒有顯示的指定@Transactional,那麼插入到資料庫中的資料就是真實的插入了。
我們的單元測試,通常涉及到資料庫的操作,那我們就需要真實的從資料庫中讀取資料並進行邏輯處理,為了保證資料庫的乾淨,也為了保證測試資料的準確性與正確性,我們最好是在做測試之前插入我們自己準備的測試資料,然後在測試完成後,將資料刪除掉,這時我們就可以通過增加一個Listener,來準備我們需要的測試資料,並和上面的交易管理相結合,就不會真正的提交到資料庫中去了。
以下這個執行個體是一個簡單的Listener實現,只是功能是把我們配置在method上面的註解裡面的設定檔路徑給列印出來,因為實現整合DBUnit並插入資料庫的代碼比較多,這裡我就不貼出來了。1.首先我們需要準備一個註解,用來標識其帶的參數為測試準備的資料檔案:DBUnitTestData.java
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Inherited@Documentedpublic @interface DBUnitTestData {public String[] dataSetLocations();}
2.編寫Listener,這個Listener的名字就定義為DBUnitTestExecutionListener.class:DBUnitTestExecutionListener.java
import org.springframework.test.context.TestContext;import org.springframework.test.context.TestExecutionListener;public class DBUnitTestExecutionListener implements TestExecutionListener {public void prepareTestInstance(TestContext testContext) throws Exception {}public void beforeTestClass(TestContext testContext) throws Exception {// Nothing to do}public void afterTestClass(TestContext testContext) throws Exception {// Nothing to do}public void beforeTestMethod(TestContext testContext) throws Exception {DBUnitTestData dbUnitRefresh = testContext.getTestMethod().getAnnotation(DBUnitTestData.class);if (dbUnitRefresh == null) {return;}String[] dataSetLocations = dbUnitRefresh.dataSetLocations();loadTestData(testContext, dataSetLocations);}public void afterTestMethod(TestContext testContext) throws Exception {// Nothing to do}private void loadTestData(TestContext testContext, String[] dataSetLocations) {if (dataSetLocations == null || dataSetLocations.length == 0) {return;}for (String dataSetLocation : dataSetLocations) {//Do what you want to do with the data set filesSystem.out.println(dataSetLocation);}}}
3.將Listener實作類別加入到測試類別的@TestExecutionListeners裡面,在方法上面增加註解@DBUnitTestData,這個時候測試類別將會是如下這樣:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { "classpath*:/spring1.xml", "classpath*:/spring2.xml" })@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class,DBUnitTestExecutionListener.class })@Transactionalpublic class TestClass {@Inject//這個類會在執行時被注入,這裡是按類型注入,如果想按名稱注入,需要加上@Named註解,如@Named("class1")//實作類別可以加上@Named("class1")註解,也可以是配置在設定檔中的Class1 class1;@Test @DBUnitTestData(dataSetLocations={"classpath:/testData/testData1.xml","classpath:/testData/testData2.xml"})public void t1(){}}
4.執行這個方法就可以看到@DBUnitTestData註解的資料檔案路徑給列印出來了。