Getting Started With ASUnit4 Within IntelliJ IDEA

Written by

Last week I was setting up an example project for RobotEyes and was using ASUnit4 which has had some tasty improvements made since version 3.  ASUnit is a collaborative effort between @lukebayes and @robpenner and has been my choice of unit testing framework for a while now.  In this blog post I will show you how to get ASUnit4 setup in IntelliJ IDEA and run a few tests taking advantage of some of the features for this new release.

AsUnit is the only open-source unit test framework for ActionScript that works with ActionScript 2, 2.5, 3.0, Flash Authoring (back to MX and up to CS4), Flex Builder, the Flex Framework (2 and 3), MTASC, MXMLC, and any version of Flash Player since version 6, including AIR and even FlashLite. We can even emit JUnit-compatible XML results. There is no dependency on any external tooling or framework.

It just works, and it works everywhere.

AsUnit4 test framework works with Flash Players 9, 10 and Adobe AIR and any version of the Flex framework. ASUnit3 tests can still be run in the latest version using Legacy Runner  (thanks to @robpenner for pointing to an example).  In ASUnit4 there are a list of significant new features and improvements including (as referenced from Luke): + Injection using SwiftSuspenders. + Speed improvements. + Composition over inheritance. + It uses annotations providing enormous flexibility. + It can swap runners at runtime thus supports legacy test cases (or even - at some point - other framework’s test cases). + It’s much easier to build custom printers. + The async functionality is much cleaner.

We will create the classes manually for this blog post, however in reality I use Project Sprouts to generate all my test classes, whats the point in doing it all manually?!

Setup your flex project in IntelliJ IDEA

I was about to do a screencast for setting up a flex project but remembered that both @jhooks and @codebum have removed the need for you to listen to my (potentially irritating) voice by recording their own extensive tutorials, so if your unsure of how to get started with IntelliJ I recommend watching their screencasts!

My final project setup screen looks like the following: Final setup Add Required Libraries to Project

  1. Download ASUnit4 and copy the asunit directory and all of its contents from the src directory to the projects src directory.
  2. Next create a lib directory in the project root and and copy into it: Reflection.swc and SwiftSuspenders-v1.5.1.swc.
  3. Click the Project Structure icon (or use cmd; or File > Project Structure) and  in Project Setting select Module > Dependencies. Select Add > Library > * New Library > Actionscript/Flex.  Name the library lib and click Add Folders With SWC browsing to your lib directory select it and click OK and then OK* again to come out of the project settings panel.

Create a Test Runner and Test Suite

  1. Within the project src create a new MXML Component (Flex 4) naming it FlexTestRunner and setting the Parent Spark component as Application.  Ensure the Class code looks as below:
  1. Next within the project test directory create a new ActionScript class and name it AllTests and ensure the Class code looks as below:

Configure IntelliJ IDEA to use ASUnit4

IntelliJ has not got in built support to compile and run ASUnit4 as it has for FlexUnit and so we have to perform two steps to compile and run:

  1. In your project root create a new directory called test then click the Project Structure icon (or use cmd; or File > Project Structure) and  in Project Setting select Module.  In the right hand panel under Sources select the newly created test directory and click the Sources button directly above the project file tree and click OK as shown below: Setting test as a source
  2. Secondly we need to create a run configuration for our tests.  Select Run > Edit Configurations and click the plus icon in the top left hand corner.  Select Flex from the drop down menu and name the new configuration TestRunner check the Main Class radio button and click the button to the left to browse to the main class, select FlexTestRunner and click OK.  You run configuration should look like below: Run Configuration

Start Writing Some Unit Tests

Now we have IntelliJ IDEA and ASUnit4 all configured plus a Test Runner and Suite let’s start looking into how to create our first UnitTest.

If you Run your TestRunner now it should run your FlexTestRunner and display no tests were found or executed with a nice little green stripe along the bottom of the window (this turns red if failed tests).  All we are going to do now is keep it simple (no package directories) and test a component which has a TextInput and a Button, on click of the button it will validate the text entered (I will re-use this logic in my up and coming example on end to end tests in Flex using RobotEyes).

1. Test the component class itself

Create a new ActionScript Class called SearchViewTest within the test directory.  The first thing we are going to do is use the new logic in ASUnit4 to inject the visual context of the test suite into the test case.  This is a handy new feature making use of SwiftSuspenders with the advantage being detailed nicely here by @stray_and_ruby:

…the idea is that the visual context of the test suite can be injected into any visual test case, rather than (as in asunit 3) having to addChild to the test case itself which forced the test cases to extend Sprite and was a bit messy. Create the injection point for the visual context as this is going to be testing out component on the display list, also add a private variable for the component we are going to test:

1
2
3
4
[Inject]
public var context:Sprite;

private var searchView:SearchView;

Now run the TestRunner, obviously this is going to flag up as a problem in our IDE as there is no SearchView component yet, so go ahead and create a new mxml component (parent spark component: Group) and name it SearchView.

Back to the test class we are going to add 3 core chunks of logic: + Before: Logic run before tests are actually initiated. + After: Logic run after tests completed. + Test: Actual test case to run.

All of the above are identified in our test class in the form of Metadata tags. Update SearchViewTest so it is the same as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Before]
        public function setUp():void
        {
            searchView=new SearchView();
            context.addChild(searchView);
        }

        [After]
        public function tearDown():void
        {
            searchView=null;
        }

        [Test]
        public function instantiated():void
        {
            assertTrue(searchView is SearchView);
        }

So lets run this new test logic, but first we need to add the test case to our test suite AllTests:

1
public var search_view_test:SearchViewTest;

Now run the TestRunner and you should see the following:

First running test

2. Test a text input of a specific id is on the components display list

Swiftly back into our test class add:

1
2
3
4
5
[Test]
        public function search_view_has_search_textinput():void
        {
            assertNotNull(searchView.searchRequest_txt);
        }

Run TestRunner and you should get a compile error as we have not yet created the text input, so within SearchView add the following code:

Run TestRunner and it should now pass.

3. Test a button of a specific id is on the components display list****

Add the following new test:

1
2
3
4
5
[Test]
        public function search_view_has_submitbutton():void
        {
            assertNotNull(searchView.submit_btn);
        }

Run TestRunner and you should get a compile error as we have not yet created the button, so within SearchView add the following code below the text input:

Run TestRunner and it should now pass.

4. Test text input text populates correctly

Add another test to confirm that text input text matches what is actually entered:

1
2
3
4
5
[Test]
        public function search_text_is_populated():void
        {
            assertSame(searchView.searchRequest_txt.text, "Hello World");
        }

This test should Fail as we have not yet entered any text, so amend the above test as below:

1
2
3
4
5
6
[Test]
        public function search_text_is_populated():void
        {
            searchView.searchRequest_txt.text="Hello World";
            assertSame(searchView.searchRequest_txt.text, "Hello World");
        }

Run TestRunner and it should now pass.

4. Test button dispatches a specific event

In our final test we will confirm the submit button dispatches a specific event and to achieve this we shall inject the IAsync interface as provided by the framework:

1
2
[Inject]
        public var async:IAsync;

And then finally add the following test and handler functions:

1
2
3
4
5
6
7
8
9
10
11
[Test]
        public function submit_button_dispatches_specific_eventname():void
        {
            searchView.addEventListener("submitSearchEvent", async.add(submitDispatchesSpecificEventType));
            searchView.submit_btn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
        }

        protected function submitDispatchesSpecificEventType(event:Event):void
        {
            assertSame(event.type, "submitSearchEvent");
        }

In order of events what is happening here is:

  1. Adding an asynchronous handler function as the event handler to the view class for the expected dispatch of an event of type submitSearchEvent when the submit_btn is clicked. The async handler uses the function submitDispatchesSpecificEventType.
  2. Manually dispatch a click event from the submit_btn.
  3. Check the event type passed into the async event handler.

Your final test class should now look like this:

Run TestRunner and it should fail. So finally add the logic in the SearchView component that will handle the button click event dispatch of a specific event submitSearchEvent:

Run the TestRunner and it should pass!

Hopefully that should serve as a gentle introduction to ASUnit4.

Note: If for some reason your test fails due to a timeout on the async handler then just increase the handler timeout duration and it should pass.

Here are some further useful links and remember the tips are in the tests:

  1. AS3
  2. Flex 3
  3. Flex 4
  4. AIR 2
  5. Test Suite
  6. Visual Test Case
  7. Async Test Case
  8. ASUnit3 Docs
  9. Keep an eye on my RobotLegs Project Sprout generators to save you a load of time creating components and their corresponding tests: https://github.com/newtriks/sprout-robotlegs

A serious shout out to @stray_and_ruby for all her patience and guidance in the realms of TDD, thank you!

Comments