2009. 12. 29. 13:58

[FlexUnit 4] 주요 특징

Test 메타데이터

이제 테스트 케이스는 [Test] 라는 메타 데이터로 표시됩니다. 더 이상 특별한 이름(test로 시작하는 등)으로 테스트를 작성하지 않아도 됩니다. 그리고 특정한 Test 와 Suite 클래스가 필요하지 않습니다. 더 이상 프레임워크 클래스를 상속할 필요도 없습니다. 여기에 몇 개의 테스트 샘플이 있습니다.

    [Test]
    public function addition():void { 
        Assert.assertEquals(12, simpleMath.add(7, 5)); 
    }
 
    [Test] 
    public function subtraction():void { 
        Assert.assertEquals(9, simpleMath.subtract(12, 3)); 
    }

더 이상 테스트 클래스가 FlexUnit 프레임워크의 클래스를 상속받지 않기 때문에, 전에 사용한 assert 함수(assertEquals, assertTrue) 가 이제 Assert 클래스의 스태틱 함수를 참조한다는 것을 알려야 합니다. 이 포스트의 후반에서 새로운 assert 방법에 대해 더 알아보도록 하겠습니다.

Before 와 After

때때로 테스트를 위해 테스트 환경을 구성할 필요가 있습니다. 위의 예에서, 테스트가 실행되기 전에 simpleMath 레퍼런스가 존재하도록 보장할 필요가 있습니다. 이를 위해 FlexUnit 과 Fluint 의 전 버전에서는 setup() 또는 teardown() 메쏘드를 오버라이드 할 수 있었습니다. FlexUnit 4 는 테스트 환경을 구성하기 위해 Before 와 After 메타데이터를 지원합니다. Before 로 표시된 모든 메쏘드는 각 테스트 메쏘드 전에 실행됩니다. After 로 표시된 모든 메쏘드는 각 테스트 메쏘드 뒤에 실행됩니다. 테스트 전후에 실행되는 복수의 메쏘드가 존재할 수 있습니다.

    [Before]
    public function runBeforeEveryTest():void { 
        simpleMath = new SimpleMath(); 
    } 
 
    [Before]
    public function alsoRunBeforeEveryTest():void { 
        simpleMath1 = new SimpleMath(); 
    } 
 
    [After] 
    public function runAfterEveryTest():void { 
        simpleMath = null; 
        simpleMath1 = null; 
    }

둘 이상의 before 또는 after 를 사용할 때, order 파라미터를 사용하여 이 메쏘드의 실행 순서를 정할 수 있습니다. 예를 들자면 [Before(order=1)][Before(order=2)].

BeforeClass 와 AfterClass

Before 와 After 로 표시된 메쏘드는 각 테스트의 전후에 실행됩니다. BeforeClass 와 AfterClass 메타 데이터를 사용하면 전체 테스트 클래스의 전후에 한 번 실행되는 스태틱 메쏘드를 정의할 수 있습니다. Before 와 After 처럼, BeforeClass 와 AfterClass 메쏘드도 하나 이상 정의할 수 있고, 순서를 정할 수 있습니다.

    [BeforeClass]
    public static function runBeforeClass():void { 
        // run for one time before all test cases 
    } 
 
    [AfterClass] 
    public static function runAfterClass():void { 
        // run for one time after all test cases 
    }

Exception 처리

Test 메타데이터는 expects 파라미터를 가질 수 있습니다. expects 파라미터는 테스트에서 예외가 발생할 것이라고 알려줍니다. 테스트에서 예외가 발생하면 성공으로 간주되고, 예외가 발생하지 않으면 실패로 간주됩니다. 그래서 try-catch 블럭으로 테스트를 감쌀 필요가 없습니다.

    [Test(expects="flash.errors.IOError")] 
    public function doIOError():void { 
        //a test which causes an IOError }Or 
 
    [Test(expects="TypeError")] 
    public function divisionWithException():void { 
        simpleMath.divide( 11, 0 );
    }

Ignore

Ignore 메타데이터는 무시하고 싶은 모든 테스트 케이스 앞에 추가될 수 있습니다. 테스트를 무시하는 이유를 추가할 수도 있습니다. 테스트를 주석 처리하는 것과 달리, 당신이 테스트를 수정하거나 완성하도록 하기 위해 이 테스트는 출력으로 나타납니다.

    [Ignore("Not Ready to Run")] 
    [Test] 
    public function multiplication():void { 
        Assert.assertEquals(15, simpleMath.multiply(3, 5)); 
    }

Async

In previous versions of FlexUnit it was difficult to have multiple asynchronous events and to test code that was event driven but not always asynchronous. Fluint provides enhanced asynchronous support including asynchronous setup and teardown, but every test carried the overhead of the asynchronous code to facilitate this feature. FlexUnit 4 allows the developer to specify which tests need asynchronous support using the async parameter. When provided, the async parameter enables the full asynchronous support provided by Fluint for that particular test. When the async parameter is specified you may also specify an optional timeout for the method.

[Before(async,timeout="250")]
public function setMeUp():void {
}
 
[After(async,timeout="250")]
public function allDone():void {
}
 
[Test(async,timeout="500")]
public function doSomethingAsynchronous():void {
   //Async.proceedOnEvent( testCase, target, eventName );
   //Async.failOnEvent( testCase, target, eventName );
   //Async.handleEvent( testCase, target, eventName, eventHandler );
   //Async.asyncHandler( testCase, eventHandler );
   //Async.asyncResponder( testCase, responder );
}

In addition to the async parameter, there are several new Async methods, each of which can also take individual timeouts, handlers and passThroughData.

Hamcrest

Earlier I alluded to new assertions. Thanks to the hamcrest-as3 project we now have the power of Hamcrest assertions. Hamcrest is based on the idea of matchers which match conditions for your assertions. For example:

[Test]
public function testGreaterThan():void {
   assertThat( 11, greaterThan(3) );
}
 
[Test]
public function isItInHere():void {
   var someArray:Array = [ 'a', 'b', 'c', 'd', 'e', 'f' ];
   assertThat( someArray, hasItems("b", "c") );
}

For more information on hamcrest:

Suites

FlexUnit 4 has a concept of test suites just like FlexUnit and Fluint. Test suites are just a collection of classes that represent tests or even other suites. A suite is defined by the [Suite] metadata. However, in FlexUnit 4, you also need to provide one additional piece of metadata called [RunWith] which instructs the test runner to execute the tests defined below using a specific class. The[RunWith] metadata forms the basis of the extensibility layer which will be discussed shortly.

[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class FlexUnitIn360 {
   public var t1:BasicMathTest;
   public var t2:MyTheory;
}

The test cases and any nested test suites, are simply defined as public variables. There is no need to instantiate them or mark them in any other way. FlexUnit’s test suite code understands how to recursively parse this class and find the tests.

User Defined Metadata Parameters

It’s often extremely useful to include additional pieces of information which are relevant to your development process when defining tests. So, for example, you might want to provide a detailed description of what a test is supposed to prove. This description could then be displayed if the test fails. Or perhaps you would like to note that a test relates to a give issue number in your bug tracking system. These custom parameters are stored by the framework when encountered during the test and can be used in reporting the success or failure later.

[Test(description="This one makes sure something works", issueID="12345")]
public function checkSomething():void {
}

Theories, Datapoints and Assumptions

This is probably the largest single new feature as it introduces a whole new way of testing. A developer can create theories, which are ‘insights’ into the way a given test should behave or over a large, potentially infinite set of values. In other words these are tests that take parameters. The parameters are defined in properties, arrays or can be retrieved from functions or other external sources. A complete description of this feature can and will take a lot of documentation, however, if you are up for reading a bit of theory, this document will introduce the ideas . Here is a quick sample of using these new techniques:

[DataPoints]
[ArrayElementType("String")]
public static var stringValues:Array = ["one","two","three","four","five"];
 
[DataPoint]
public static var values1:int = 2;
[DataPoint]
public static var values2:int = 4;
 
[DataPoints]
[ArrayElementType("int")]
public static function provideData():Array {
   return [-10, 0, 2, 4, 8, 16 ];
}
 
[Theory]
public function testDivideMultiply( value1:int, value2:int ):void {
   assumeThat( value2, greaterThan( 0 ) );
 
   var div:Number = simpleMath.divide( value1, value2 );
   var mul:Number = simpleMath.multiply( div, value2 );
 
   Assert.assertEquals( mul, value1 );
}      
 
[Theory]
public function testStringIntCombo( value:int, stringValue:String ):void {
   //call some method and do something
}

In this case, there are datapoints defined by static properties as well as method calls. The framework introspects the datapoints and uses this data combined along with any type specified in the ArrayElementType metadata. This information is used in combination with the theory method signatures to call each theory for each possible combination of parameters.

RunWith

FlexUnit 4 is nothing more than a set of runners combined to run a complete set of tests. A runner is a class that implements a specific interface and understands how to find, execute and report back information about any tests in a given class. Each time a new class is encountered, FlexUnit 4 works through a list of possible runners and attempts to identify the correct one to execute the tests contained in the class.

The RunWith metadata allows you to override the default choice made by the framework and specify a different class to act as the runner. This feature allows developers to write entirely new types of runners, with support for new features, which can work directly with the existing framework and report their results back through the same interface.
In the case of the suite, you are instructing the framework to run this class in a specialized runner that simply finds the correct runner for all of the classes it contains.

[RunWith("org.flexunit.runners.Suite")]

Adapters

Using the flexibility of the multiple runners discussed above, the new FlexUnit 4 framework has legacy runners built in for both FlexUnit 1 and Fluint tests. This means that FlexUnit 4 is completely backwards compatible; all existing FlexUnit and Fluint tests can be run, and even mixed into suites with FlexUnit 4 tests without any code changes.

Further, supplemental runners are in development for FUnit and several other testing projects

User Interface Facade

Lastly FlexUnit 4 provides a UIComponent testing facade which allows you to add or remove components from the display list. This allows you to accurately test component methods in a real runtime state. This feature creates a foundation for other projects to extend into areas of integration and functional testing without the need for extensive rewrites or modifications.

[Before(async,ui)]
public function setUp():void {
   //Create a textInput, add it to the testEnvironment. Wait until it is created, then run tests on it
   textInput = new TextInput();
   Async.proceedOnEvent( this, textInput, FlexEvent.CREATION_COMPLETE, 200 );
   UIImpersonator.addChild( textInput );
}

Additional documentation on these and other features will become available as the project progresses.

'Adobe > FlexUnit' 카테고리의 다른 글

[FlexUnit 4] 소개  (0) 2009.12.29