摘要:软件开发和软件测试就像两兄弟,他们密不可分、协同合作,目标只有一个,那就是成功开发出高质量的软件。开发与测试之间的关系如此密切,让我们很难彻底的将两者严格的划分开来。单元测试做为测试的一部分,一般都由编码人员来承担,对于模块级一直都是谁编码、谁测试。因此测试不仅仅是测试人员的事情,作为编码人员也需要懂得测试的基本方法,以通过单元测试提交高质量的程序模块。
关键字:NetBeans,Junit,单元测试
1 引言:
任何一个程序员都知道单元测试的重要性,没有经过严格测试的模块是“靠不住”的,组装过程会出现越来越多的Bug,甚至到了客户那里都不能正常工作,这简直就是一场灾难。虽然每个程序员都深刻的知道这点,但是很多时候在进度的压力下,程序员不得不放弃部分甚至是全部的单元测试。特别是在我国现在的国情下,献礼项目太多,建设方的领导为了在某个“有意义”的日子里使项目上线,往往迫使软件开发方违背客观事实,在不可能的工期内完工。程序员作为项目的最底层人员,自然没有力量来进行反抗,当他们加班加点都无法在规定时间完成,于是放弃测试就成为了他们的唯一选择。
很快这就成为一个恶性循环:压力越大,编写的测试越少。编写的测试越少,的效率越低,并且代码越不稳定。而效率越低并且越不精确,开发人员就感觉越有压力。
程序员的精力就在这样的恶性循环中被耗费掉。想要打破它需要一种外界的影响。所谓的这种外界的影响,其实就是一个简单的测试框架,它可以让我们通过做很少的测试,来达到完整的测试,减少我们编写测试代码的时间。
2 NetBeans 5.0对单元测试的支持
NetBeans IDE 5.0 引入了对基于 NetBeans 平台的 IDE 模块和富客户端程序开发的全面支持,直观的全新
GUI Builder Matisse,经过重新设计的对 CVS 的新支持,对 Sun Application Server 8.2、Weblogic9
和 JBoss 4 的支持,以及很多的编辑器增强功能。同时集成了Java开发工具中应用最广泛的单元测试工具Junit,使得在NetBeans下进行单元测试变得简单容易,提高了程序员进行单元测试的积极性。
可以使用 NetBeans IDE 创建以下类型的测试:
- 空测试:没有测试方法的测试框架,尚未指定要测试的任何类。
- 现有类的测试:包含实际测试方法的类,这些方法镜像了要测试的源的结构。
- 测试套件:汇集在一起的几组测试类,允许对整个应用程序或项目进行测试。
可以使用以下方法生成并找到测试:在“项目”窗口中选择任何类或包节点,然后从“工具”> "JUnit"
菜单中进行选择。NetBeans 将单元测试表示为子树,这些子树反映了项目的 Java 包结构。每个测试类都由它所测试的类的名称后Test
单词组成(如 MyClassTest.java)。
每个项目都有一个缺省的测试包,所有的测试文件都在测试包内被组织。程序文件与测试文件被分割成两个独立的部分,在项目下分为一个SRC文件夹和一个TEST文件夹,互相不产生影响,测试完成后,只需要将SRC文件夹单独移开,并不需要TEST文件夹的支持。包结构如下图:
3 被测试模块的编写
新建一个Java类库的项目,项目名称为:MoneyChange,新建包moneychange,在包中添加类Money.class。(为了阅读方便,下面代码中原来的注释已经被删除)
package moneychange;
public class Money {
private int fAmount;
private String fCurrency;
public Money(int amount,String
currency) {
fAmount=amount;
fCurrency=currency;
}
public int amount()
{
return
fAmount;
}
public String currency()
{
return
fCurrency;
}
public Money add(Money
m)
{
return
new Money(amount()+m.amount(),currency());
}
public boolean equals(Object
anObject)
{
if(anObject
instanceof Money)
{
Money aMoney=(Money)anObject;
return aMoney.currency().equals(currency())
&& amount()==aMoney.amount();
}
return false;
}
}
该类有两个私有属性fAmount和fCurrency,构造函数在对类进行初始化的时候,对两个私有属性进行了赋值。Add方法对两个Money对象的现金(fAmount)进行相加,equals方法对两个Money对象的现金及货币单位进行比较是否相等。
4 创建单元测试
在项目窗口中的类Money.class上鼠标右键单击,在弹出的菜单中选择“工具”,并在子菜单中选择“创建Junit测试”,如下图所示:
这并不是创建单元测试的唯一方法,也可以通过“工具”下拉菜单中的“创建Junit测试”进行。接着弹出“创建测试”对话框,对测试类的类名以及需要生成的内容进行选择后,点击“确定”即可完成测试类的生成。如下图:
5 测试代码的修改
Junit不是万能的,不要指望它什么都帮你做好,在单元测试中,Junits 负责测试框架的生成,其他的事情还是需要程序员来做,如测试用例的设计和测试管理等。Junit针对上面代码生成的测试代码如下(已经删除部分注释):
package moneychange;
import junit.framework.*;
public class MoneyTest extends TestCase
{
public MoneyTest(String
testName) {
super(testName);
}
protected void
setUp() throws Exception {
}
protected void
tearDown() throws Exception {
}
/**
* amount
方法的测试(属于类 moneychange.Money)。
*/
public void testAmount()
{
System.out.println("amount");
Money instance = null;
int expResult = 0;
int result = instance.amount();
assertEquals(expResult, result);
// TODO
查看生成的测试代码并删除会失败的缺省调用。
fail("测试案例为原型。");
}
/**
* currency
方法的测试(属于类 moneychange.Money)。
*/
public void testCurrency()
{
System.out.println("currency");
Money instance = null;
String expResult = "";
String result = instance.currency();
assertEquals(expResult, result);
// TODO 查看生成的测试代码并删除会失败的缺省调用。
fail("测试案例为原型。");
}
/**
* add 方法的测试(属于类
moneychange.Money)。
*/
public void testAdd()
{
System.out.println("add");
Money m = null;
Money instance = null;
Money expResult = null;
Money result = instance.add(m);
assertEquals(expResult, result);
// TODO 查看生成的测试代码并删除会失败的缺省调用。
fail("测试案例为原型。");
}
/**
* equals
方法的测试(属于类 moneychange.Money)。
*/
public void testEquals()
{
System.out.println("equals");
Object anObject = null;
Money instance = null;
boolean expResult = true;
boolean result = instance.equals(anObject);
assertEquals(expResult, result);
// TODO 查看生成的测试代码并删除会失败的缺省调用。
fail("测试案例为原型。");
}
}
此时,如果要执行测试,可以展开项目中的测试包,在测试类上鼠标右键单机,在弹出的菜单上选择“运行文件”,如下图所示。
默认的测试类的执行结果是全部都不能通过的,结果如下:
我们需要对生成的测试代码进行修改,将我们的测试用例以及期望的结果写入测试代码中,将fail(“测试案例为原型”);语句删除。testAdd的代码修改后如下:
public void testAdd() {
System.out.println("testAdd");
// TODO add your test
code below by replacing the default call to fail.
// fail("The test
case is empty.");
// Ceate the objects
we will use during the test. These objects are commonly
// referred to as a test'sfixture.
All we need for the testAdd test are some
// Money objects.
Money m12CHF= new Money(12,
"CHF");
Money m14CHF= new Money(14,
"CHF");
Money expected= new Money(26,
"CHF");
// Exercise the objects
in the fixture
Money result= m12CHF.add(m14CHF);
// Verify the result
Assert.assertTrue(expected.equals(result));
}
该方法创建了两个进行加法操作的对象m12CHF和m14CHF,相加的结果为result对象,然后将result与期望的对象expected对象进行相等性测试。对修改后的测试代码再次执行结果如下:
对所有的测试用例进行测试通过后,即可以开始填写单元测试报告。通过单元测试的类比没有经过测试的类的稳定性将大大提高。
6 总结
NetBeans集成的Junit单元测试工具为单元测试提供了一个很好的框架,我们无需将精力浪费在写单元测试代码上,而将更多的关注测试用例的设计。开发人员进行测试越来越方便,这也增强了开发人员进行单元测试的信心,在赶工期的同时将单元测试做好,是保证项目最后能够成功,不成为“无底洞”的一个重要手段。
|