转:测试驱动开发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方法中,比如:关闭数据库连接,关闭流……
原文地址:https://www.cnblogs.com/youxin/p/3081232.html