FlexUnit单元测试

  常见的几种测试:

   一、单元测试:单元测试是对软件中的基本组成单位进行的测试,如一个模块、一个过程等等。它是软件动态测试的最基本的部分,也是最重要的部分之一,其目的是检验软件基本组成单位的正确性。一个软件单元的正确性是相对于该单元的规约而言的。因此,单元测试以被测试单位的规约为基准。单元测试的主要方法有控制流测试、数据流测试、排错测试、分域测试等等。

    二、集成测试:集成测试是在软件系统集成过程中所进行的测试,其主要目的是检查软件单位之间的接口是否正确。它根据集成测试计划,一边将模块或其他软件单位组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各组成部分是否合拍。集成测试的策略主要有自顶向下和自底向上两种。 
        
三、系统测试:系统测试是对已经集成好的软件系统进行彻底的测试,以验证软件系统的正确性和性能等满足其规约所指定的要求,检查软件的行为和输出是否正确并非一项简单的任务,它被称为测试的 “ 先知者问题 ” 。因此,系统测试应该按照测试计划进行,其输入、输出和其他动态运行行为应该与软件规约进行对比。软件系统测试方法很多,主要有功能测试、性能测试、随机测试等等。
 
        
四、验收测试:验收测试旨在向软件的购买者展示该软件系统满足其用户的需求。它的测试数据通常是系统测试的测试数据的子集。所不同的是,验收测试常常有软件系统的购买者代表在现场,甚至是在软件安装使用的现场。这是软件在投入使用之前的最后测试。
 
        
五、回归测试:回归测试是在软件维护阶段,对软件进行修改之后进行的测试。其目的是检验对软件进行的修改是否正确。这里,修改的正确性有两重含义:一是所作的修改达到了预定目的,如错误得到改正,能够适应新的运行环境等等;二是不影响软件的其他功能的正确性。

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()分别的测试MyCirclelengtharea的方法。方法里,我们用到了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,它的类型为TestSuiteTestSuite是一个装载测试的容器,也就是说,我们的要把我们的测试类分别加到这个容器上,如:

       suite.addTest( new MyCircleTest( "testLength" ) );

suite.addTest(new MyCircleTest("testArea"));

new MyCircleest(“testLength”);语句中,我们那函数testLength()的方法名作为参数,那么在TestCase里,就把methodName属性赋值为”testLength”,那么就表明了在这个TestCase对象里,我们要调用的测试方法是testLength( )

之后,我们新建一个TestRunnerBase类的实例testRunnerTestRunnerBasePanel的子类,那么它就是一个可显示的组件,它的test属性我们附值为suite,接着我们就可以开始测试了,也就调用testRunnerstartTest()函数。

FlexUnit单元测试(第二章FlexUnit基本应用) - 小斌 - 有志、有识、有恒、有为

上图就是我们那见到的运行结果,如果测试全面通过,即图的右方会出现“√”的符号,如果测试不通过,就会出现如图所示:

FlexUnit单元测试(第二章FlexUnit基本应用) - 小斌 - 有志、有识、有恒、有为

图右方的文字写出了错误的详细说明,通过它显示的数据,我们可以很清晰的看到那个类的那个方法出错,从而友好地帮助编程人员测试代码。

 

在说明问题之前,大家就看一个例子:

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);

        }

}

这里,我们运行的时候,会发现程序在等待:

FlexUnit单元测试(第三章FlexUnit事件断言) - 小斌 - 有志、有识、有恒、有为

 

3秒之后就会出现如下结果:

 

FlexUnit单元测试(第三章FlexUnit事件断言) - 小斌 - 有志、有识、有恒、有为

 

 

这里有一点要注意,如果我们这样写:

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 对象中的每个测试方法运行一次,而非对这个测试用例运行一次。

 

 

原文地址:https://www.cnblogs.com/tinytiny/p/2760450.html