随笔 - 3, 文章 - 152, 评论 - 17, 引用 - 0
数据加载中……

单元测试-入门篇

前面的一篇文章(单元测试-理论篇)讨论了什么是单元测试、单元测试的优点并列举了很多不写单元测试的借口。如果你同意我们的观点,认同单元测试确实是软件开发中不可缺少的过程,那么我们就开始单元测试之旅吧!


一个比较最大值的函数
  我们首先引入一个比较最大值的函数。我们传入一个类型为int的数组参数,它将返回最大值的那个元素。代码如下:
public class Largest {
 public static int largest(int[] datas){
  int max = 0;
  
  for(int i = 0 ; i < datas.length ; i++){
   if(max < datas[i]){
    max = datas[i];
   }
  }
  return max;
 }
}
  可是,如何写我们的测试代码呢?


直接在Largest类中添加一个main方法,要么重新写一个可运行的类来测试Largest。这样的测试,同样给我们带来了很大的挑战:
1、 验证困难。如何去验证代码的行为和我们的期望一致呢?使用很多的if…else再加上==或equals()来判断?对异常的情况又如何处理呢?混乱的验证,很容易给我们的测试代码带来BUG,让我们对自己的测试不够自信。
2、 测试类无法管理。我们如何直观的得到测试运行成功或失败的消息?用原始的System.out.println()吗?我们能一次运行多个单元测试吗?如果前面的测试运行出现异常,后面的测试还能继续运行吗?如果测试类很多,上百个甚至更多,我们能方便的由控制台输出测试结果吗?
3、 无法统计测试代码覆盖情况。缺少统一的测试代码编写规范和约定,可读性和维护性差。
不过,面对这些挑战不用沮丧。单元测试框架已经帮我们解决了这些问题,它提供了很多测试的基础设施,让我们能把更多的经历投入到测试代码的编写中来。


JUnit
JUnit最初是由Erich Gamma(GoF之一)和Kent Beck(xp和refactor的先驱之一)编写的,它是一个开源的Java测试框架,用于编写和运行可重复的测试。


下面我们逐步介绍如何对Largest类测试:
一、 JUnit的安装。如果你使用的开发工具是Eclipse,不用做任何安装,它已经提供了Junit的支持。否则,你需要去http://www.junit.org/ 下载Junit安装包。安装非常简单,只要将junit.jar包设置到ClassPath中,让你的Java代码能够找到它就可以了。
二、 编写测试代码。代码如下:
    public class LargestTest extends TestCase {
  public void testLargest(){
   int[] datas = {7,8,9};
   assertEquals(9,Largest.largest(datas));
  }
}
说明:
1、 测试类一般要继承抽象类TestCase。它实现了各种测试方法,并提供了一个测试过程的架构。
2、 测试代码通过断言(Assert)来判断某个被测试函数是否正常工作。JUnit提供了很多断言函数,用来确定:某个条件是否为真;两个数据是否相等,或者不等,或者其它的一些情况。
3、 测试方法名以“test”开头,这样JUnit框架会自动发现这是一个测试方法。

三、 运行测试类。
   运行测试成功。

我们的单元测试这样就算完成了吗?不,上面的测试只能算是一次验证而已。我们给的数据中,最大值9是数组的最后一个元素,如果9是第一个元素它还正确吗?如果数据是负数呢?等等。我们的求最大值函数有着很多的边界情况需要单元测试来验证。
   因此,我们在写单元测试之前,一定要对测试做一个周全的计划,预先设置好要测试的内容,可能发生错误的边界条件。
下面是对Largest做的测试计划:
1、 数组元素的位置是否对最大值产生影响?
l [7,8,9] – 9
l [7,9,8] – 9
l [9,8,7] – 9
2、 如果有两个相等的最大值,会出现什么情况呢?
l [7,9,8,9] – 9
3、如果数组中只有一个元素,结果会怎么样?
l [1] - 1
4、 如果元素都是负数呢?
l [-7,-8,-9] - -7
完整的测试代码应该如下:
public class LargestTest extends TestCase {
 
 public void testSimple(){
  assertEquals(9,Largest.largest(new int[]{7,8,9}));
 }
 public void testOrder(){
  assertEquals(9,Largest.largest(new int[]{7,9,8}));
  assertEquals(9,Largest.largest(new int[]{9,8,7}));
 }
 public void testDups(){
  assertEquals(9,Largest.largest(new int[]{7,9,8,9}));
 }
 public void testOne(){
  assertEquals(1,Largest.largest(new int[]{1}));
 }
 public void testNegative(){
   assertEquals(-7,Largest.largest(new int[]{-7,-8,-9}));
 }
}
当然,你可以写完一个测试方法就立即来运行它。这次并没有那么幸运了,在运行最后一个测试方法testNegative()时出现了错误:
junit.framework.AssertionFailedError: expected:<-7> but was:<0>
 at test.junit.LargestTest.testNegative(LargestTest.java:24)
细心的你,也许在一开始就发现了Largest的这个Bug。原来我们的字段max初始化为0是不对的,应该改为Integer.MIN_VALUE。
由此我们可以想到,使用单元测试确实可以尽早的发现隐藏的BUG,上一篇我们也说过,越早发现BUG就能节省更多的时间,降低更多的风险。
这是,我们的单元测试已经完美结束了吗?呵呵,也许你会想到,如果在largest()方法中传入数组为空,又会怎么样呢?这个问题留给我们的读者思考吧。


写到这里,算是入门结束了吧!关于JUnit的详细介绍,网上有非常多的文章,去google你可以找到一大堆。下面我提供几个不错的单元测试网站,希望能对你有所帮助:
51Testing-无忧软件测试网:http://www.51testing.com/
测试时代:http://www.testage.net/
UML软件工程组织-软件测试:http://www.uml.org.cn/Test/test.asp
测试管理中心:http://www.testmanager.com.cn/
软件工程专家网:http://www.51cmm.com/
开放软件测试研究:http://www.opentest.net/

posted on 2005-04-11 14:46 阅读(218) 评论(0)  编辑  收藏 所属分类: 测试


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问