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方法中,比如:关闭数据库连接,关闭流……
  • 相关阅读:
    菜单导航组件
    flask+nginx+uwsgi在服务器搭建项目
    安装Anaconda
    vscode上eslink包失效
    js滚动事件
    打字游戏
    js更高文档的样式
    js事件
    Dom对象更改文档结构.html
    js重点
  • 原文地址:https://www.cnblogs.com/youxin/p/3081232.html
Copyright © 2011-2022 走看看