<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks

    淺談TDD

    測試驅動開發,它是敏捷開發的最重要的部分。方法主要是先根據客戶的需求編寫測試程序,然后再編碼使其通過測試。在敏捷開發實施中,開發人員主要從兩個方面去理解測試驅動開發。

    a)在測試的輔助下,快速實現客戶需求的功能。通過編寫測試用例,對客戶需求的功能進行分解,并進行系統設計。我們發現從使用角度對代碼的設計通常更符合后期開發的需求。可測試的要求,對代碼的內聚性的提高和復用都非常有益。
    b)在測試的保護下,不斷重構代碼,提高代碼的重用性,從而提高軟件產品的質量。可見測試驅動開發實施的好壞確實極大的影響軟件產品的質量,貫穿了軟件開發的始終。
    在測試驅動開發中,為了保證測試的穩定性,被測代碼接口的穩定性是非常重要的。否則,變化的成本就會急劇的上升。所以,自動化測試將會要求您的設計依賴于接口,而不是具體的類。進而推動設計人員重視接口的設計,體現系統的可擴展性和抗變性。


    JUnit4的用法介紹

    Java 語言現在支持泛型、枚舉、可變長度參數列表和注釋,這些特性為可重用的框架設計帶來了新的可能。
    JUnit4利用 Java 5 的新特性(尤其是注釋)的優勢,使得單元測試比起用最初的 JUnit 來說更加簡單。

    測試方法 @Test

    以前所有版本的 JUnit 都使用命名約定和反射來定位測試。例如,下面的代碼測試 1 + 1 等于 2:

     

    import junit.framework.TestCase;
    public class AdditionTest extends TestCase {
    private int x = 1;
    private int y = 1;
    public void testAddition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }


    而在 JUnit4 中,測試是由 @Test 注釋來識別的,如下所示:

    import org.junit.Test;
    import junit.framework.TestCase;
    public class AdditionTest {
    private int x = 1;
    private int y = 1;
    @Test
    public void testAddition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }

    使用注釋來識別測試方法的優點是不再需要將所有的方法命名為 testAddition()、testXXX()的形式等等。
    例如,下面的方法也可以工作:

    import org.junit.Test;
    import junit.framework.TestCase;
    public class AdditionTest {
    private int x = 1;
    private int y = 1;
    @Test
    public void addition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }

    使用這種方法的好處是:
    a)允許我們遵循最適合的應用程序的命名約定。
    我們可以將測試方法使用與被測試的類相同的名稱(由開發組規范約定)。例如,LoginAction.login() 由 LoginActionTest.login()方法測試、LoginAction.check()由LoginActionTest.check()方法測試等等。
    b)使用JUnit4后,測試用例類可以不繼承TestCase類,所以我們也就可以擴展被測試類了。
    這種方法使得測試受保護的方法非常容易,我們只要將測試用例類繼承被測試類,就可以測試受保護方法了。

    @Before(SetUp)

    JUnit 3 測試運行程序會在運行每個測試之前自動調用 setUp() 方法。該方法一般會初始化字段、準備數據等等。例如下面的 setUp() 方法,用于設定要加載的路由文件:

     

    public void setUp() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }



    在 JUnit4 中,我們仍然可以在每個測試方法運行之前初始化字段或準備數據。然而,完成這些操作的方法不再需要叫做 setUp(),只要用 @Before 注釋來指示該方法即可,如下所示:

     

    @Before
    public void initialize() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }



    JUnit4允許我們使用 @Before 來注釋多個方法,這些方法都在每個測試之前運行:

     

    @Before
    public void initialize() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }

    @Before
    public void prepareRetData() {
    //
    }



    @After(TearDown)

    清除方法與初始化方法類似。在 JUnit3 中,我們要將方法命名為 tearDown() 才可以實現清除方法,但在JUnit4中,只要給方法添加@After標注即可。
    例如:

     

        @After
    public static void clearContext() {
    ActionContext.getContext().put(StrutsStatics.HTTP_REQUEST, 
    null);
    ActionContext.setContext(
    null);
    }



    測試方法結束后清除為此測試用例準備的一些數據。
    與 @Before 一樣,也可以用 @After 來注釋多個清除方法,這些方法都在每個測試之后運行。
    最后,我們不再需要顯式調用在超類中的初始化和清除方法,只要它們不被覆蓋,測試運行程序將根據需要自動為您調用這些方法。
    超類中的 @Before 方法在子類中的 @Before 方法之前被調用(這反映了構造函數調用的順序)。
    @After 方法以反方向運行:子類中的方法在超類中的方法之前被調用。否則,多個 @Before 或 @After 方法的相對順序就得不到保證。


    @Before和@After小結

    假設測試類中有如下方法定義:

     

    @Before
    public void init(){}
    @After
    public void destroy(){}

    則Before、After方法的執行流程如圖所示:

    淺談TDD

    測試驅動開發,它是敏捷開發的最重要的部分。方法主要是先根據客戶的需求編寫測試程序,然后再編碼使其通過測試。在敏捷開發實施中,開發人員主要從兩個方面去理解測試驅動開發。

    a)在測試的輔助下,快速實現客戶需求的功能。通過編寫測試用例,對客戶需求的功能進行分解,并進行系統設計。我們發現從使用角度對代碼的設計通常更符合后期開發的需求。可測試的要求,對代碼的內聚性的提高和復用都非常有益。
    b)在測試的保護下,不斷重構代碼,提高代碼的重用性,從而提高軟件產品的質量。可見測試驅動開發實施的好壞確實極大的影響軟件產品的質量,貫穿了軟件開發的始終。
    在測試驅動開發中,為了保證測試的穩定性,被測代碼接口的穩定性是非常重要的。否則,變化的成本就會急劇的上升。所以,自動化測試將會要求您的設計依賴于接口,而不是具體的類。進而推動設計人員重視接口的設計,體現系統的可擴展性和抗變性。


    JUnit4的用法介紹

    Java 語言現在支持泛型、枚舉、可變長度參數列表和注釋,這些特性為可重用的框架設計帶來了新的可能。
    JUnit4利用 Java 5 的新特性(尤其是注釋)的優勢,使得單元測試比起用最初的 JUnit 來說更加簡單。

    測試方法 @Test

    以前所有版本的 JUnit 都使用命名約定和反射來定位測試。例如,下面的代碼測試 1 + 1 等于 2:

     

    import junit.framework.TestCase;
    public class AdditionTest extends TestCase {
    private int x = 1;
    private int y = 1;
    public void testAddition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }


    而在 JUnit4 中,測試是由 @Test 注釋來識別的,如下所示:

     

    import org.junit.Test;
    import junit.framework.TestCase;
    public class AdditionTest {
    private int x = 1;
    private int y = 1;
    @Test
    public void testAddition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }


    使用注釋來識別測試方法的優點是不再需要將所有的方法命名為 testAddition()、testXXX()的形式等等。
    例如,下面的方法也可以工作:

     

    import org.junit.Test;
    import junit.framework.TestCase;
    public class AdditionTest {
    private int x = 1;
    private int y = 1;
    @Test
    public void addition() {
    int z = x + y;
    assertEquals(
    2, z);
    }

    }


    使用這種方法的好處是:
    a)允許我們遵循最適合的應用程序的命名約定。
    我們可以將測試方法使用與被測試的類相同的名稱(由開發組規范約定)。例如,LoginAction.login() 由 LoginActionTest.login()方法測試、LoginAction.check()由LoginActionTest.check()方法測試等等。
    b)使用JUnit4后,測試用例類可以不繼承TestCase類,所以我們也就可以擴展被測試類了。
    這種方法使得測試受保護的方法非常容易,我們只要將測試用例類繼承被測試類,就可以測試受保護方法了。

    @Before(SetUp)

    JUnit 3 測試運行程序會在運行每個測試之前自動調用 setUp() 方法。該方法一般會初始化字段、準備數據等等。例如下面的 setUp() 方法,用于設定要加載的路由文件:

     

    public void setUp() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }


    在 JUnit4 中,我們仍然可以在每個測試方法運行之前初始化字段或準備數據。然而,完成這些操作的方法不再需要叫做 setUp(),只要用 @Before 注釋來指示該方法即可,如下所示:

     

    @Before
    public void initialize() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }


    JUnit4允許我們使用 @Before 來注釋多個方法,這些方法都在每個測試之前運行:

     

    @Before
    public void initialize() {
    // 加載此測試用例的servicerouting配置文件
    ServiceRouting.loadConfig("com/demo/servicerouting.conf");
    // 
    }

    @Before
    public void prepareRetData() {
    //
    }



    @After(TearDown)

    清除方法與初始化方法類似。在 JUnit3 中,我們要將方法命名為 tearDown() 才可以實現清除方法,但在JUnit4中,只要給方法添加@After標注即可。
    例如: 

       @After
    public static void clearContext() {
    ActionContext.getContext().put(StrutsStatics.HTTP_REQUEST, 
    null);
    ActionContext.setContext(
    null);
    }


    測試方法結束后清除為此測試用例準備的一些數據。
    與 @Before 一樣,也可以用 @After 來注釋多個清除方法,這些方法都在每個測試之后運行。
    最后,我們不再需要顯式調用在超類中的初始化和清除方法,只要它們不被覆蓋,測試運行程序將根據需要自動為您調用這些方法。
    超類中的 @Before 方法在子類中的 @Before 方法之前被調用(這反映了構造函數調用的順序)。
    @After 方法以反方向運行:子類中的方法在超類中的方法之前被調用。否則,多個 @Before 或 @After 方法的相對順序就得不到保證。


    @Before和@After小結

    假設測試類中有如下方法定義:

     

    @Before
    public void init(){}
    @After
    public void destroy(){}

    則Before、After方法的執行流程如圖所示:


    這種方法有明顯的缺陷,如果要初始化的是數據庫的鏈接,或者是一個大的對象的話,而這些資源恰恰是整個測試用例類可以共用的,每次都去申請,確實是種浪費。所以JUnit4引入了@BeforeClass和@AfterClass。


    @BeforeClass和@AfterClass

    JUnit4 也引入了一個 JUnit3 中沒有的新特性:類范圍的 setUp() 和 tearDown() 方法。任何用 @BeforeClass 注釋的方法都將在該類中的測試方法運行之前剛好運行一次,而任何用 @AfterClass 注釋的方法都將在該類中的所有測試都運行之后剛好運行一次。
    例如,假設類中的每個測試都使用一個數據庫連接、一個非常大的數據結構,或者申請其他一些資源。不要在每個測試之前都重新創建它,您可以創建它一次,用完后將其銷毀清除。該方法將使得有些測試案例運行起來快得多。
    注意:被注釋為 BeforeClass和AfterClass 的方法必須為static方法。
    用法如下:

        @BeforeClass
    public static void classInit() {
    Map callRet 
    = new HashMap();
    List
    <ErrorCodeMessageBean> list = new ArrayList<ErrorCodeMessageBean>();
    list.add(createMsgBean(
    "TDE0001""第一個錯誤消息"));
    list.add(createMsgBean(
    "TDP9999""格式化{0}{1}"));
    list.add(createMsgBean(
    "TDE1000~TDF0001""區間錯誤消息"));
    list.add(createMsgBean(
    "TDG0001~""有下限的區間錯誤消息"));
    list.add(createMsgBean(
    "~TDD0001""有上限的區間錯誤消息"));
    list.add(createMsgBean(
    "~""默認的消息"));
    callRet.put(ErrorCodeMessageBean.codeMsgBeanKey, list);
    ServiceCall.expectLastCallReturn(callRet);
    }

    @Test
    public void oneTestMethod() {
    //.
    }

    @AfterClass
    public static void classDestroy() {
    ServiceCall.expectLastCallReturn(
    null);
    }

    這個特定雖然很好,但是一定要小心對待這個特性。它有可能會違反測試的獨立性,并引入非預期的混亂。如果一個測試在某種程度上改變了 @BeforeClass 所初始化的一個對象,那么它有可能會影響其他測試的結果。也就是說,由BeforeClass申請或創建的資源,如果是整個測試用例類共享的,那么盡量不要讓其中任何一個測試方法改變那些共享的資源,這樣可能對其他測試方法有影響。它有可能在測試套件中引入順序依賴,并隱藏 bug。

    BeforeClass和AfterClass的執行流程如下:

    這種方法有明顯的缺陷,如果要初始化的是數據庫的鏈接,或者是一個大的對象的話,而這些資源恰恰是整個測試用例類可以共用的,每次都去申請,確實是種浪費。所以JUnit4引入了@BeforeClass和@AfterClass。


    @BeforeClass和@AfterClass

    JUnit4 也引入了一個 JUnit3 中沒有的新特性:類范圍的 setUp() 和 tearDown() 方法。任何用 @BeforeClass 注釋的方法都將在該類中的測試方法運行之前剛好運行一次,而任何用 @AfterClass 注釋的方法都將在該類中的所有測試都運行之后剛好運行一次。
    例如,假設類中的每個測試都使用一個數據庫連接、一個非常大的數據結構,或者申請其他一些資源。不要在每個測試之前都重新創建它,您可以創建它一次,用完后將其銷毀清除。該方法將使得有些測試案例運行起來快得多。
    注意:被注釋為 BeforeClass和AfterClass 的方法必須為static方法。
    用法如下:

       @BeforeClass
    public static void classInit() {
    Map callRet 
    = new HashMap();
    List
    <ErrorCodeMessageBean> list = new ArrayList<ErrorCodeMessageBean>();
    list.add(createMsgBean(
    "TDE0001""第一個錯誤消息"));
    list.add(createMsgBean(
    "TDP9999""格式化{0}{1}"));
    list.add(createMsgBean(
    "TDE1000~TDF0001""區間錯誤消息"));
    list.add(createMsgBean(
    "TDG0001~""有下限的區間錯誤消息"));
    list.add(createMsgBean(
    "~TDD0001""有上限的區間錯誤消息"));
    list.add(createMsgBean(
    "~""默認的消息"));
    callRet.put(ErrorCodeMessageBean.codeMsgBeanKey, list);
    ServiceCall.expectLastCallReturn(callRet);
    }

    @Test
    public void oneTestMethod() {
    //.
    }

    @AfterClass
    public static void classDestroy() {
    ServiceCall.expectLastCallReturn(
    null);
    }

    這個特定雖然很好,但是一定要小心對待這個特性。它有可能會違反測試的獨立性,并引入非預期的混亂。如果一個測試在某種程度上改變了 @BeforeClass 所初始化的一個對象,那么它有可能會影響其他測試的結果。也就是說,由BeforeClass申請或創建的資源,如果是整個測試用例類共享的,那么盡量不要讓其中任何一個測試方法改變那些共享的資源,這樣可能對其他測試方法有影響。它有可能在測試套件中引入順序依賴,并隱藏 bug。

    BeforeClass和AfterClass的執行流程如下:




    測試異常@Test(expected=XXXException.class)

    異常測試是 JUnit4 中的最大改進。舊式的異常測試是在拋出異常的代碼中放入 try 塊,然后在 try 塊的末尾加入一個 fail() 語句。
    例如,該方法測試被零除拋出一個 ArithmeticException:

     

    public void testDivisionByZero() {
    try {
    int n = 2 / 0;
    fail(
    "Divided by zero!");
    }

    catch (ArithmeticException success) {
    assertNotNull(success.getMessage());
    }

    }


    該方法不僅難看,而且寫起來也繁瑣。在 JUnit 4 中,我們現在可以編寫拋出異常的代碼,并使用注釋來聲明該異常是預期的:

     

        @Test(expected = BusinessException.class)
    public void testExecuteNameEmpty() throws Exception {
    BookList bListAction 
    = new BookList();
    bListAction.setName(
    "");
    bListAction.execute();
    }


    附被測試代碼(如果輸入name為empty,則拋出BusinessException,若name不為"liming",則拋出MessageException異常):

        @Override
    public String execute() throws Exception {
    if (StringUtils.isEmpty(name)) {
    throw new BusinessException("~""name cant't empty.");
    }

    if (!StringUtils.equals("liming", name.trim())) {
    throw new MessageException(name + " have no limits.");
    }

    Map ret 
    = serviceCall.call(JMockService.queryDtlInfo, null);
    orderId 
    = (String) ret.get("OrderId");
    dataList 
    = (List) ret.get("Data");
    return SUCCESS;
    }


    參數化測試

    為了保證單元測試的嚴謹性,我們經常要模擬很多種輸入參數,來確定我們的功能代碼是可以正常工作的,為此我們編寫大量的單元測試方法。可是這些測試方法都是大同小異:代碼結構都是相同的,不同的僅僅是測試數據和期望輸出值。
    JUnit4 的參數化測試方法給我們提供了更好的方法,將測試方法中相同的代碼結構提取出來,提高代碼的重用度,減少復制粘貼代碼的痛苦。
    例如下面的功能代碼(格式化字符串,將駝峰規則的字符串以"_"分隔):

     

    public class WordDealUtil {
    public static String wordFormat4DB(String name) {
    if (name == null{
    return null;
    }

    Pattern p 
    = Pattern.compile("[A-Z]");
    Matcher m 
    = p.matcher(name);
    StringBuffer sb 
    = new StringBuffer();
    while (m.find()) {
    if (m.start() != 0{
    m.appendReplacement(sb, (
    "_" + m.group()).toLowerCase());
    }

    }

    return m.appendTail(sb).toString().toLowerCase();
    }

    }


    沒有使用參數化的測試用例代碼:

    public class WordDealUtilTest {
    /**
    * 測試 null 時的處理情況
    */

    @Test
    public void wordFormat4DBNull() {
    String target 
    = null;
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertNull(result);
    }

    /**
    * 測試空字符串的處理情況
    */

    @Test
    public void wordFormat4DBEmpty() {
    String target 
    = "";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "", result);
    }

    /**
    * 測試當首字母大寫時的情況
    */

    @Test
    public void wordFormat4DBegin() {
    String target 
    = "EmployeeInfo";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_info", result);
    }

    /**
    * 測試當尾字母為大寫時的情況
    */

    @Test
    public void wordFormat4DBEnd() {
    String target 
    = "employeeInfoA";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_info_a", result);
    }

    /**
    * 測試多個相連字母大寫時的情況
    */

    @Test
    public void wordFormat4DBTogether() {
    String target 
    = "employeeAInfo";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_a_info", result);
    }

    }

    看以上測試用例代碼,結構相似,只是輸入值與期望輸出不同而已,但我們要拷貝很多代碼。
    使用參數化的測試用例代碼:

    @SuppressWarnings("unchecked")
    @RunWith(Parameterized.
    class)
    public class WordDealUtilTestWithParam {
    private String expected;
    private String target;
    @Parameters
    public static Collection words() {
    return Arrays.asList(new Object[][] {
    "employee_info""employeeInfo" },  // 測試一般的處理情況
    nullnull },                         // 測試 null 時的處理情況
    """" },                             // 測試空字符串時的處理情況
    "employee_info""EmployeeInfo" },    // 測試當首字母大寫時的情況
    "employee_info_a""employeeInfoA" }// 測試當尾字母為大寫時的情況
    "employee_a_info""employeeAInfo" }  // 測試多個相連字母大寫時的情況
    }
    );
    }

    /**
    * 參數化測試必須的構造函數
    @param expected     期望的測試結果,對應參數集中的第一個參數
    @param target     測試數據,對應參數集中的第二個參數
    */

    public WordDealUtilTestWithParam(String expected, String target) {
    this.expected = expected;
    this.target = target;
    }

    /**
    * 測試將 Java 對象名稱到數據庫名稱的轉換
    */

    @Test
    public void wordFormat4DB() {
    Assert.assertEquals(expected, WordDealUtil.wordFormat4DB(target));
    }

    }

    很明顯,代碼簡單且很清晰了。在靜態方法 words 中,我們使用二維數組來構建測試所需要的參數列表,其中每個數組中的元素的放置順序并沒有什么要求,只要和構造函數中的順序保持一致就可以了。現在如果再增加一種測試情況,只需要在靜態方法 words 中添加相應的數組即可,不再需要復制粘貼出一個新的方法出來了。
    這種參數化的測試用例寫法,很適用于一些共用的功能方法。



    測試異常@Test(expected=XXXException.class)

    異常測試是 JUnit4 中的最大改進。舊式的異常測試是在拋出異常的代碼中放入 try 塊,然后在 try 塊的末尾加入一個 fail() 語句。
    例如,該方法測試被零除拋出一個 ArithmeticException:

     

    public void testDivisionByZero() {
    try {
    int n = 2 / 0;
    fail(
    "Divided by zero!");
    }

    catch (ArithmeticException success) {
    assertNotNull(success.getMessage());
    }

    }


    該方法不僅難看,而且寫起來也繁瑣。在 JUnit 4 中,我們現在可以編寫拋出異常的代碼,并使用注釋來聲明該異常是預期的:

       @Test(expected = BusinessException.class)
    public void testExecuteNameEmpty() throws Exception {
    BookList bListAction 
    = new BookList();
    bListAction.setName(
    "");
    bListAction.execute();
    }

    附被測試代碼(如果輸入name為empty,則拋出BusinessException,若name不為"liming",則拋出MessageException異常):
        @Override
    public String execute() throws Exception {
    if (StringUtils.isEmpty(name)) {
    throw new BusinessException("~""name cant't empty.");
    }

    if (!StringUtils.equals("liming", name.trim())) {
    throw new MessageException(name + " have no limits.");
    }

    Map ret 
    = serviceCall.call(JMockService.queryDtlInfo, null);
    orderId 
    = (String) ret.get("OrderId");
    dataList 
    = (List) ret.get("Data");
    return SUCCESS;
    }


    參數化測試

    為了保證單元測試的嚴謹性,我們經常要模擬很多種輸入參數,來確定我們的功能代碼是可以正常工作的,為此我們編寫大量的單元測試方法。可是這些測試方法都是大同小異:代碼結構都是相同的,不同的僅僅是測試數據和期望輸出值。
    JUnit4 的參數化測試方法給我們提供了更好的方法,將測試方法中相同的代碼結構提取出來,提高代碼的重用度,減少復制粘貼代碼的痛苦。
    例如下面的功能代碼(格式化字符串,將駝峰規則的字符串以"_"分隔):

    public class WordDealUtil {
    public static String wordFormat4DB(String name) {
    if (name == null{
    return null;
    }

    Pattern p 
    = Pattern.compile("[A-Z]");
    Matcher m 
    = p.matcher(name);
    StringBuffer sb 
    = new StringBuffer();
    while (m.find()) {
    if (m.start() != 0{
    m.appendReplacement(sb, (
    "_" + m.group()).toLowerCase());
    }

    }

    return m.appendTail(sb).toString().toLowerCase();
    }

    }


    沒有使用參數化的測試用例代碼: 

    public class WordDealUtilTest {
    /**
    * 測試 null 時的處理情況
    */

    @Test
    public void wordFormat4DBNull() {
    String target 
    = null;
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertNull(result);
    }

    /**
    * 測試空字符串的處理情況
    */

    @Test
    public void wordFormat4DBEmpty() {
    String target 
    = "";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "", result);
    }

    /**
    * 測試當首字母大寫時的情況
    */

    @Test
    public void wordFormat4DBegin() {
    String target 
    = "EmployeeInfo";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_info", result);
    }

    /**
    * 測試當尾字母為大寫時的情況
    */

    @Test
    public void wordFormat4DBEnd() {
    String target 
    = "employeeInfoA";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_info_a", result);
    }

    /**
    * 測試多個相連字母大寫時的情況
    */

    @Test
    public void wordFormat4DBTogether() {
    String target 
    = "employeeAInfo";
    String result 
    = WordDealUtil.wordFormat4DB(target);
    assertEquals(
    "employee_a_info", result);
    }

    }


    看以上測試用例代碼,結構相似,只是輸入值與期望輸出不同而已,但我們要拷貝很多代碼。
    使用參數化的測試用例代碼:

    @SuppressWarnings("unchecked")
    @RunWith(Parameterized.
    class)
    public class WordDealUtilTestWithParam {
    private String expected;
    private String target;
    @Parameters
    public static Collection words() {
    return Arrays.asList(new Object[][] {
    "employee_info""employeeInfo" },  // 測試一般的處理情況
    nullnull },                         // 測試 null 時的處理情況
    """" },                             // 測試空字符串時的處理情況
    "employee_info""EmployeeInfo" },    // 測試當首字母大寫時的情況
    "employee_info_a""employeeInfoA" }// 測試當尾字母為大寫時的情況
    "employee_a_info""employeeAInfo" }  // 測試多個相連字母大寫時的情況
    }
    );
    }

    /**
    * 參數化測試必須的構造函數
    @param expected     期望的測試結果,對應參數集中的第一個參數
    @param target     測試數據,對應參數集中的第二個參數
    */

    public WordDealUtilTestWithParam(String expected, String target) {
    this.expected = expected;
    this.target = target;
    }

    /**
    * 測試將 Java 對象名稱到數據庫名稱的轉換
    */

    @Test
    public void wordFormat4DB() {
    Assert.assertEquals(expected, WordDealUtil.wordFormat4DB(target));
    }

    }

    很明顯,代碼簡單且很清晰了。在靜態方法 words 中,我們使用二維數組來構建測試所需要的參數列表,其中每個數組中的元素的放置順序并沒有什么要求,只要和構造函數中的順序保持一致就可以了。現在如果再增加一種測試情況,只需要在靜態方法 words 中添加相應的數組即可,不再需要復制粘貼出一個新的方法出來了。
    這種參數化的測試用例寫法,很適用于一些共用的功能方法。

    posted on 2010-12-15 15:34 李 明 閱讀(13222) 評論(1)  編輯  收藏 所屬分類: JUnit

    評論

    # re: JUnit4用法詳解 2010-12-15 17:12 mashiguang
    先收藏  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 久久九九全国免费| 亚洲乱码在线播放| 国产亚洲成av片在线观看| 亚洲国产一成久久精品国产成人综合| 成全视频免费高清| 永久免费视频v片www| 成人毛片18女人毛片免费| 成人毛片18女人毛片免费视频未| 美女视频黄是免费的网址| 最近免费中文字幕4| 永久免费av无码网站大全| 国产精品国产午夜免费福利看| 精品久久免费视频| 免费v片在线观看品善网| 亚洲男人的天堂在线va拉文| 国产亚洲精品高清在线| 国产亚洲欧洲精品| 亚洲伊人久久大香线蕉苏妲己| 亚洲成AV人片久久| 亚洲日韩AV一区二区三区中文| 国产精品亚洲专区无码WEB | 四虎影视免费永久在线观看| 亚洲AV无码乱码精品国产| 国产亚洲大尺度无码无码专线| 亚洲不卡中文字幕无码| 亚洲精品在线播放视频| 中文字幕在线观看亚洲日韩| 美女视频黄a视频全免费网站色 | 亚洲精品日韩专区silk| 亚洲精品无码成人片久久不卡 | 亚洲无砖砖区免费| 亚洲欧美乱色情图片| 男人扒开添女人下部免费视频| 色www永久免费| 最近在线2018视频免费观看| 大香人蕉免费视频75| 亚洲无码高清在线观看| 久久精品国产亚洲77777| 亚洲精品av无码喷奶水糖心| aa级毛片毛片免费观看久| 美丽的姑娘免费观看在线播放|