第8章 单元测试工具
单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。
在一种传统的结构化编程语言中,比如C语言,要进行测试的单元一般是函数或子过程。在像C++这样的面向对象的语言中,要进行测试的基本单元是类。对Ada语言来说,开发人员可以选择是在独立的过程或函数,还是在Ada包的级别上进行单元测试。单元测试的原则同样被扩展到第四代语言(4GL)的开发中,在这里基本单元被典型地划分为一个菜单或显示界面。
本章介绍单元测试工具JUnit 4。JUnit 4是JUnit的第四个版本,而JUnit属于Xunit系列的单元测试工具的产品(另外,还有CPPUnit、CUnit、C#Unit等)。
本章主要内容为:
l 单元测试工具JUnit 4如何在Eclipse中使用
8.1 单元测试工具JUnit 4如何在Eclipse中使用
百度百科介绍:
“JUnit是一个Java语言的单元测试框架,由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit和xUnit家族中最成功的一个。JUnit有自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试工具。
JUnit是由Erich Gamma和Kent Beck编写的一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用JUnit进行自动测试了。”
而JUnit 4是JUnit框架有史以来的最大改进,其主要目标是利用Java 5的Annotation特性简化测试用例的编写。
8.1.1 JUnit 4环境的配置
注:使用JUnit 4时不要使用第11章提供的ADT配置的Eclipse,这个Eclipse在JUnit 4中存在一些问题。可以到Eclipse的官方网站(http://www.eclipse.org/)上下载J2SE版本。笔者目前使用的版本如图8-1所示。
图8-1 Eclipse
首先需要有被测程序,这里以一个简易的计算器作为例子。
案例8-1:简易的计算器。
这个计算器中主要包括加、减、乘、除、求平方以及开根号6个函数,其代码如下:
package com.jerrg; public class Calculator { private static int result; // 静态变量,用于存储运行结果 public void add(int m,int n) { result = m + n; } public void substract(int m,int n) { result = n-m; //Bug: 正确的应该是result =m-n } public void multiply(int m,int n) { } // 此方法尚未写好 public void divide(int m,int n) { result = m / n; } public void square(int n) { result = n * n; } public void squareRoot(int n) { for (; ;) ; //Bug : 死循环 } public void clear() { // 将结果清零 result = 0; } public int getResult() { return result; } }
注:这里暂时先不写乘法函数的实现,并且故意写错减法函数的实现。
接下来建立JUnit 4测试程序。首先将JUnit 4单元测试包引入这个Project:在被测程序的Class上单击鼠标右键,在弹出的菜单上选择【Properties】,然后在弹出的属性窗口中,首先在左边选择【Java Build Path】,然后到右上选择【Libraries】标签,之后在最右边选择【Add Library…】按钮,如图8-2所示。
图8-2 Java Build Patch
在Eclipse的Package Explorer中右键单击该弹出菜单,选择“New a JUnit 4 Test Case”,在弹出的对话框中进行相应的选择,如图8-3所示。
图8-3 New JUnit Test Case
单击【下一步】按钮后,系统自动列出这个类中包含的方法,选择要进行测试的方法。此例中,仅对“加、减、乘、除”4个方法进行测试。之后系统会自动生成一个新类CalculatorTest,里面包含一些空的测试用例。只需对这些测试用例稍作修改,即可使用。
packagecom.jerry; importstatic org.junit.Assert.*; importorg.junit.Before; importorg.junit.Test; importorg.junit.Ignore; publicclass CalculatorTest { privatestatic Calculator calculator = new Calculator(); @Before publicvoid setUp() throws Exception { calculator.clear(); } @Test publicvoid testAdd() { calculator.add(2,3); assertEquals(5,calculator.getResult()); } @Test publicvoid testSubstract() { calculator.substract(10,2); assertEquals(8,calculator.getResult()); } @Test publicvoid testMultiply() { fail("Not yetimplemented"); } @Test publicvoid testDivide() { calculator.divide(8,2); assertEquals(4,calculator.getResult()); } }
注:这里暂时先不写乘法函数的测试代码。
8.1.2 Junt4测试用例的运行和调试
写好产品代码和测试代码后,就可以运行测试程序了。只要在Eclipse的CalculatorTest类上单击鼠标右键,在弹出的菜单上选择“Run As a JUnit Test”运行测试用例,测试结果就显示出来了,如图8-4所示。
显然,减法没通过是由于代码中存在问题,而乘法没通过是由于乘法没有实现。首先来修改减法的函数实现:
publicvoid substract(int m,int n) { result =n-m; //Bug: 正确的应该是result =m-n }
再进行一次运行,结果如图8-5所示。
图8-4 JUnit单元测试结果(一)
图8-5 JUnit单元测试结果(二)
最后完成乘法的产品代码与测试代码。产品代码如下:
publicvoid multiply int m,int n) { result=m*n }
测试代码如下:
publicvoid testMultiply() { calculator.multiply(8,2); assertEquals(16,calculator.getResult()); }
图8-6为最后的测试结果。最终产品代码如下:
packageandycpp; publicclass Calculator { private static int result; // 静态变量,用于存储运行结果 public void add(int m,int n) { result = m + n; } public void substract(int m,int n) { result = m-n; } public void multiply int m,int n) { result = m*n; } public void divide(int m,int n) { result = m / n; } public void square(int n) { result = n * n; } public void squareRoot(int n) { for (; ;) ; //Bug : 死循环,为了后面介绍 } public void clear() { // 将结果清零 result = 0; } public int getResult() { return result; } }
图8-6 JUnit单元测试结果(三)
而最终的测试代码如下:
packagecom.jerry; importstatic org.junit.Assert.*; importorg.junit.Before; importorg.junit.Test; importorg.junit.Ignore; publicclass CalculatorTest { privatestatic Calculator calculator = new Calculator(); @Before publicvoid setUp() throws Exception { calculator.clear(); } @Test publicvoid testAdd() { calculator.add(2,3); assertEquals(5,calculator.getResult()); } @Test publicvoid testSubstract() { calculator.substract(10,2); assertEquals(8,calculator.getResult()); } @Test publicvoid testMultiply() { calculator.multiply (8,2); assertEquals(16,calculator.getResult()); }@Test publicvoid testDivide() { calculator.divide(8,2); assertEquals(4,calculator.getResult()); } }
顾翔凡言:
不是好的工作会给你带来好的心情,而是好的心情会给你带来好的工作。