常见的几种测试:
一、单元测试:单元测试是对软件中的基本组成单位进行的测试,如一个模块、一个过程等等。它是软件动态测试的最基本的部分,也是最重要的部分之一,其目的是检验软件基本组成单位的正确性。一个软件单元的正确性是相对于该单元的规约而言的。因此,单元测试以被测试单位的规约为基准。单元测试的主要方法有控制流测试、数据流测试、排错测试、分域测试等等。
二、集成测试:集成测试是在软件系统集成过程中所进行的测试,其主要目的是检查软件单位之间的接口是否正确。它根据集成测试计划,一边将模块或其他软件单位组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各组成部分是否合拍。集成测试的策略主要有自顶向下和自底向上两种。 三、系统测试:系统测试是对已经集成好的软件系统进行彻底的测试,以验证软件系统的正确性和性能等满足其规约所指定的要求,检查软件的行为和输出是否正确并非一项简单的任务,它被称为测试的 “ 先知者问题 ” 。因此,系统测试应该按照测试计划进行,其输入、输出和其他动态运行行为应该与软件规约进行对比。软件系统测试方法很多,主要有功能测试、性能测试、随机测试等等。 四、验收测试:验收测试旨在向软件的购买者展示该软件系统满足其用户的需求。它的测试数据通常是系统测试的测试数据的子集。所不同的是,验收测试常常有软件系统的购买者代表在现场,甚至是在软件安装使用的现场。这是软件在投入使用之前的最后测试。 五、回归测试:回归测试是在软件维护阶段,对软件进行修改之后进行的测试。其目的是检验对软件进行的修改是否正确。这里,修改的正确性有两重含义:一是所作的修改达到了预定目的,如错误得到改正,能够适应新的运行环境等等;二是不影响软件的其他功能的正确性。
FlexUnit的特点:
FlexUnit 最大的特点就是提供了对事件的断言支持。
FlexUnit的根本组成:
同其他流行的单元测试框架一样,FlexUnit 提供了测试方法(test method),测试用例(test case)和测试套件(test suite)的概念。
测试方法:
测试方法是测试的基本单元,包括一系列的断言用以对被测试对象的特定功能或特性进行测试。 在一些测试框架,如UnitF中,测试方法必须是 public的,并且方法名必须以“test”开头,利用反射查找符合条件的测试方法并运行测试。而FlexUnit则使用了methodName属性,程序员可以自行指定所要测试的方法。
测试用例
通常是一系列测试方法的集合用以对同一个被测试对象进行测试。在FlexUnit中,测试用例必须继承自 TestCase 类。
测试套件
是对一系列测试用例或测试套件的集合,用以组织测试。添加进测试套件的测试可以是测试用例,也可以是其他的测试套件,测试套件会套嵌的执行每个测试方法
明白了测试的概念后,现在就介绍FlexUnit单元测试吧。FlexUnit可以说是Junit的一个复制,因为它们具有太多的相似性,不过说白了,其实所有的单元测试都是一个样,主要的方法就是通过输入来比较输出的结果是否正确。虽说原理是这么简单,但是一个好的单元测试框架,可以为编程人员带来很好的方便,在FlexUnit中,当然也有一个很有的框架。要使用FlexUnit,先须先下载FlexUnit.swc,这是一个集成的单元测试包,下载后导入即可使用。请先看看一个简单的例子:
public class MyCircle
{
private var _radiusX:int;
private var _radiusY:int;
private var _r:int;
private var _length:Number;
private var _area:Number;
public function MyCircle() {
this._r = 0;
this._radiusX = 0;
this._radiusY = 0;
this._length = 0;
this._area = 0;
}
public function get radiusX():int { return _radiusX; }
public function set radiusX(value:int):void {
_radiusX = value;
}
public function get r():int { return _r; }
public function set r(value:int):void {
_r = value;
}
public function get radiusY():int { return _radiusY; }
public function set radiusY(value:int):void {
_radiusY = value;
}
public function get length():Number {
_length = 2 * _r * Math.PI;
_length = Math.round(_length);
return _length;
}
public function get area():Number {
_area = Math.PI * _r * _r;
return _area;
}
}
我们有一个待测试的类MyCircle,现在我们要测试两个函数:get length()(周长)、get area()(面积)。为了测试,我们编写了如下的测试类:
import flexunit.framework.Assert;
import flexunit.framework.TestCase;
public class MyCircleTest extends TestCase
{
public function MyCircleTest(methodName:String) {
super(methodName);
}
public function testLength():void{
var myCircle:MyCircle = new MyCircle();
myCircle.r = 50;
var result:Number = myCircle.length;
Assert.assertEquals(result,Math.round(Math.PI * 100));
}
public function testArea():void{
var myCircle:MyCircle = new MyCircle();
myCircle.r = 50;
var result:Number = myCircle.area;
Assert.assertEquals(result,50*50*Math.PI+1);
}
}
MyCircleTest类是TestCase的一个子类,一般的情况下,我们都要继承TestCase这个类,TestCase是运行多个测试方法的装置,它有一个methodName的属性,表示用来测试的方法名, textLength()、textArea()分别的测试MyCircle的length、area的方法。方法里,我们用到了Assert类,Assert可以说是一个用来判断结果的测试类,它提供了很多方法,如:
assertEquals(),如何参数相等就运行正确,不等就会抛出一个错误
assertNull( ) ->判断参数是否为Null;
assertUndefined( ) ->判断参数是否未定义;
在一切都建立好后,再编写mxml:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()"
xmlns:flexui="flexunit.flexui.*"
>
<mx:Script>
<![CDATA[
import flexunit.framework.TestSuite;
import flexunit.flexui.TestRunnerBase ;
private function init():void
{
var suite:TestSuite = new TestSuite();
suite.addTest(new MyCircleTest("testLength"));
suite.addTest(new MyCircleTest("testArea"));
testRunner.test = suite;
testRunner.startTest();
}
]]>
</mx:Script>
<flexui:TestRunnerBase id="testRunner" width="100%" height="100%" />
</mx:Application>
在这里,我们定义了一个变量suite,它的类型为TestSuite,TestSuite是一个装载测试的容器,也就是说,我们的要把我们的测试类分别加到这个容器上,如:
suite.addTest( new MyCircleTest( "testLength" ) );
suite.addTest(new MyCircleTest("testArea"));
在new MyCircleest(“testLength”);语句中,我们那函数testLength()的方法名作为参数,那么在TestCase里,就把methodName属性赋值为”testLength”,那么就表明了在这个TestCase对象里,我们要调用的测试方法是testLength( )。
之后,我们新建一个TestRunnerBase类的实例testRunner,TestRunnerBase是Panel的子类,那么它就是一个可显示的组件,它的test属性我们附值为suite,接着我们就可以开始测试了,也就调用testRunner的startTest()函数。
上图就是我们那见到的运行结果,如果测试全面通过,即图的右方会出现“√”的符号,如果测试不通过,就会出现如图所示:
图右方的文字写出了错误的详细说明,通过它显示的数据,我们可以很清晰的看到那个类的那个方法出错,从而友好地帮助编程人员测试代码。
在说明问题之前,大家就看一个例子:
import flexunit.framework.TestCase;
import flexunit.framework.Assert;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class TimerTest extends TestCase {
private var _timerCount:int;
public function TimerTest(methodName:String) {
super(methodName);
_timerCount = 0;
}
public function testTimer():void {
var timer:Timer = new Timer(3000, 1);
timer.addEventListener(TimerEvent.TIMER, incrementCount);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, verifyCount);
timer.start();
}
private function incrementCount(timerEvent:TimerEvent):void {
_timerCount++;
}
private function verifyCount(timerEvent:TimerEvent):void {
Assert. assertEquals(1, _timerCount);
}
}
我们要对testTimer()方法进行测试,程序很简单,当我们测试testTimer时,内里并没有抛出任何错误,因此我们看到的结果是正确的,但是当3秒过后,程序会自动执行verifyCount( )函数,这函数体里有assertEquals(1,_timerCount) 这个语句,显然,我们在incrementCount( )方法里把_timerCount增加了,因为timer只执行一次,所以_timerCount的值应为1,那么我们比较的结果应该是正确的。但如果我们这样写呢:
Assert. assertEquals(100, _timerCount);
我们可以看到,TestRunnerBase里依然显示正确,这是为什么呢?因为这个比较是在3秒后才执行的,在测试testTimer( )的时间只需短短的十几毫秒,那时并没有抛出任何错误,当testTimer( )执行完毕,该testcase便会被清除,于是就认为测试通过。
说到这里,大家就会开始想解决以上问题的方法。在FlexUnit中,使用了addAsync()这个函数来解决上述问题。下面我们介绍addAsync( )函数的用法:
addAsync( )有四个参数:
1、 触发的事件函数。
2、 监听的时间,单位为毫秒。
3、 事件函数的参数,类型为Object,默认为空。
4、 失败所要调用的函数,如果在指定时间内没有触发事件,则断言失败。默认为空。
另外,addAsync()方法的返回值是一个函数。
我们把上面的例子改为:
public class TimerTest extends TestCase {
private var _timerCount:int;
public function TimerTest(methodName:String) {
super(methodName);
_timerCount = 0;
}
public function testTimer():void {
var timer:Timer = new Timer(3000, 1);
timer.addEventListener(TimerEvent.TIMER, incrementCount);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(verifyCount , 3500) );
timer.start();
}
private function incrementCount(timerEvent:TimerEvent):void {
_timerCount++;
}
private function verifyCount(timerEvent:TimerEvent):void {
Assert. assertEquals(15, _timerCount);
}
}
这里,我们运行的时候,会发现程序在等待:
3秒之后就会出现如下结果:
这里有一点要注意,如果我们这样写:
public function testTimer():void {
addAsync(verifyCount, 5000);
_timer = new Timer(3000, 1);
_timer.addEventListener(TimerEvent.TIMER, verifyCount );
_timer.start();
}
或者这样写:
public function testTimer():void {
var function:Function = verifyCount;
addAsync(function, 5000);
_timer = new Timer(3000, 1);
_timer.addEventListener(TimerEvent.TIMER, function);
_timer.start();
}
都会提示为:“Asynchronous function did not fire after 5000 ms”这样的错误。这是为什么呢?明明在5秒的时间内verifyCount函数被执行了。
但是当然们改成这样时:
public function testTimer():void {
var function:Function = addAsync(verifyCount, 5000);
_timer = new Timer(3000, 1);
_timer.addEventListener(TimerEvent.TIMER, function);
_timer.start();
}
结果就正确了,那么大家就可以猜到,我们使用addAsync(verifyCount, 5000) 方法,并不是断言verifyCount是否被执行了,而是断言addAsync()方法所返回的函数是否被执行了,如果有执行,我们就调用verifyCount方法,如果没有就断言失败。
另外要提一下的是,TestCase里还有setUp( )和tearDown( )两个函数。setUp 方法将在每个测试方法之前运行,用于搭建通用的初始设置。 tearDown方法将在每个测试方法之后运行,用于进行通用的卸载或清除工作。 setUp 和 tearDown 方法是该 TestCase 对象中的每个测试方法运行一次,而非对这个测试用例运行一次。