zoukankan      html  css  js  c++  java
  • 转:测试驱动开发With JUnit(一)

    试驱动开发(TDD)是极限编程(XP)的重要特点,它是以持续性的测试来推动代码的开发,即可以简化代码,又可以保证质量。它改变了先编写代码,后编写测试,而是先编写测试,然后在编写代码来满足测试的方法。这样使得测试工作不仅仅是单纯的测试,而成为了设计的一部分。对于刚入门的编程者来说,也许觉得非常地别扭,但是当你习惯了这种编程方式之后,你会发现,TDD会成为你的得力助手。
          下面的内容就以学习JUnit这个测试工具来简单的介绍TDD。(注:本文主要内容是介绍JUnit的使用,顺便抛砖引玉介绍TDD的开发过程。想了解更多关于TDD,可以参考其他的一些专业书籍)。
          开发环境是:Eclipse3.2,已经集成了JUnit,所以就对Junit的配置不做介绍(网上这种文章太多了)。

    第一章:JUnit快速入门:
           需求:需要一个工具类,可以实现2个数的加、减、乘、除四个功能。我们给这个类起名叫CalculateUtil。
           先编写测试代码:
     
     
    1. import junit.framework.TestCase;                //1行   
    2. public class CalculateUtilTest extends TestCase  //2行   
    3. {   
    4.     public void testCreate()                     //3行   
    5.     {   
    6.         new CalculateUtil();   
    7.     }   
    8. }  
          代码解释:
          1行:导入JUnit必须的类
          2行:任何一个测试类必须集成TestCase类。
                    测试类的类名命名   方式:被测试类类名+Test。这是一种比较好的习惯,
                    比如从CalculateUtilTest这个名称就知道被测试类是CalculateUtil
           3行:测试类的测试方法。所有的测试方法都必须以test单词开头,并且方法的返
                    回类型为void。
           编写完测试代码之后在Eclipse中运行该测试类,发现Junit运行出错(显示了一条红色杠)

           这是在预料之中,因为我们还没有编写CalculateUtil类。为了使测试通过,那么下面开始编写CalculateUtil类。CalculateUtil类代码如下:

     
     
    1. public class CalculateUtil   
    2. {   
    3. }  

            然后再次运行测试类。这时会发现测试成功。
           
     
    1. import junit.framework.TestCase;   
    2. public class CalculateUtilTest extends TestCase   
    3. {   
    4.     public void testCreate()                    //1行   
    5.     {   
    6.         CalculateUtil ca=new CalculateUtil();       
    7.         assertEquals(5, ca.add(3,2));             //2行   
    8.     }   
    9. }  

           在这里代码稍微改变了一下,使用ca引用来指向生成的CalculateUtil对象。
           代码解释:
           1行:测试类的方法必须以单词test开头
           2行:assertEquals()方法。以assert单词开头的方法就是JUnit测试框架中的断    
                    言方法。比如assertEquals(5, ca.add(3,2)); 方法就是断言ca的add(3,2)方
                    法返回的结果等于5。如果add(3,2)返回5那么测试成功,否则测试失败。
             运行测试类,这时测试失败。那么向CalculateUtil中添加代码来保证测试成功:
     
     
    1. public class CalculateUtil   
    2. {   
    3.     public int add(int numOne,int numTwo)   
    4.     {   
    5.         return numOne+numTwo;   
    6.     }   
    7. }  

           为了验证add方法是否是真的返回两个数的相加的结果,我们继续在添加一行测试代码:
     
     
    1. assertEquals(7, ca.add(4,2));  
        再运行会发现测试出错
          故障跟踪中错误描述为:
          junit.framework.AssertionFailedError:expected:<7> but was <6>
          (如果你英语不是很差的话,相信这句话不用我解释也明白了)。在测试的时候,要选用一些容易出错的边界值进行测试,有正确的测试用例也要有错误的测试用例。
         在完成add方法之后,下面开始进行除法的编写。首先编写测试代码:
     
     
    1. import junit.framework.TestCase;   
    2. public class CalculateUtilTest extends TestCase   
    3. {   
    4.     public void testCreate()   
    5.     {   
    6.         CalculateUtil ca=new CalculateUtil();   
    7.         assertEquals(5, ca.add(3,2));               
    8.     }   
    9.     public void testDivision()   
    10.     {   
    11.         CalculateUtil ca=new CalculateUtil();   
    12.         assertEquals("两个数相除"2,ca.division(42));  //1行   
    13.     }   
    14. }  

          代码解释:
          1行:assertEquals("两个数相除", 2,ca.division(4, 2));和前面assertEquals方法  
                   不一样,该方法多了一个参数,这个参数就是对该测试的一个简单的描述。
           如果测试失败,那么会有提示。
           为了使测试通过,就要在CalculateUtil类中添加一个division方法。代码如下:
     
    1. public class CalculateUtil   
    2. {   
    3.     public int add(int numOne,int numTwo)   
    4.     {   
    5.         return numOne+numTwo;   
    6.     }   
    7.     
    8.     public int division(int numOne,int numTwo)   
    9.     {   
    10.         return numOne/numTwo;   
    11.     }   
    12. }  

            运行测试代码,测试通过。那么这样就可以了吗?由于除法非常特殊,如果除数为0那么会怎么样呢?我们继续在testDivision()中添加一行测试代码测试除数为0的情况:
     
     
    1. public void testDivision()   
    2. {   
    3.     CalculateUtil ca=new CalculateUtil();   
    4.     assertEquals("两个数相除"2,ca.division(42));    
    5.     assertEquals("除数为0:"2,ca.division(4,0));   
    6. }  

           运行测试,会发现testDivision()方法抛出了异常。
     
           测试表明:当除数为0的时,方法division()生成了一个异常。那么我们希望在测试用例中捕获该异常。更改后的testDivision()方法如下: 
     
     
    1. public void testDivision()   
    2. {   
    3.     CalculateUtil ca=new CalculateUtil();   
    4.     assertEquals("两个数相除:"2,ca.division(4,2));   
    5.     try  
    6.     {   
    7.         assertEquals("除数为0:"2,ca.division(4,0));   
    8.         fail("除数不为0");                          //1行   
    9.     }   
    10.     catch(ArithmeticException ex){}   
    11. }  
     
          代码解释:fail()一旦被执行,会立即中止测试,java虚拟机不再执行任何别的代码,并且会抛出junit.framework.AssertionFailedError异常。结合上面的try-catch语句,如果产生异常,那么会忽略fail()方法,如果没有产生异常那么就会调用fail()方法使测试失败,用这种方式就可以测试是否有异常产生,如果抛出异常,那么测试通过,否则测试失败。再次运行测试用例,一条绿杠显示测试通过。
           但是这样还是不妥,因为类CalculateUtil毕竟是不知道测试类的存在,虽然在测试类中用异常捕获,但是一旦脱离测试类,那么division()方法的健壮性还是受到质疑。所以从新修改division()方法
     
     
    1. public int division(int numOne,int numTwo)throws ArithmeticException   
    2. {   
    3.     return numOne/numTwo;   
    4. }  

           再重新运行测试用例,测试通过。
    注:处理异常的方式很多,这里只是其中一种做法。也可以在division()方法中写一段业务逻辑,判断numTwo是否为0,如果为0则抛出异常等……,在这里不做深入讨论。
            从刚才的几个例子中,可以大概的知道TDD的开发思路,也知道JUnit的基本用法。但当我们反观CalculateUtilTest 类中的测试方法可以发现:类中的两个测试方法都构造了CalculateUtil的对象ca,但是对于程序来说,我们只需要构造一个对象即可。我们可以对CalculateUtilTest类中的代码稍作修改。修改后代码如下:
     
     
    1. public class CalculateUtilTest extends TestCase   
    2. {   
    3.     private CalculateUtil ca;   
    4.     protected void setUp() throws Exception    //1行   
    5.     {   
    6.         ca=new CalculateUtil();                    
    7.     }   
    8.     
    9.     public void testCreate()   
    10.     {   
    11.         assertEquals(5, ca.add(3,2));   
    12.         assertEquals(7, ca.add(4,2));   
    13.     }   
    14.     
    15.     public void testDivision()   
    16.     {   
    17.         CalculateUtil ca=new CalculateUtil();   
    18.         assertEquals("两个数相除:"2,ca.division(4,2));   
    19.         try  
    20.         {   
    21.             assertEquals("除数为0:"2,ca.division(4,0));   
    22.             fail("除数不为0");                            
    23.         }   
    24.         catch(ArithmeticException ex){}   
    25.     }   
    26. }  

           代码解释:
           1行:JUnit在执行每个测试之前都先执行setUp方法,可以将公共的测试初始化代码放在setUp方法中。与setUp功能方法相反的是protected void tearDown() throws Exception方法;可以将测试结束后要执行的收尾工作放入tearDown方法中,比如:关闭数据库连接,关闭流……
  • 相关阅读:
    printcap
    browser-ua
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 72 编辑距离
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode 71 简化路径
    Java实现 LeetCode70 爬楼梯
  • 原文地址:https://www.cnblogs.com/youxin/p/3081232.html
Copyright © 2011-2022 走看看