asunit testing with flash cs3 and actionscript 3

Unit tests are supposed to be the first things you write when following an extreme programming or rapid development methodology, but I seldom found the time to bother until recently. On a Flex Data Services project, we needed to interact with a complex and evolving application programing interface. Our coping strategy was to write flexunit tests for every interaction with our J2EE backend. We were using the Cairngorm framework, which uses value objects and business delegates to abstract communication with a remote service. I wrote a separate test harness application which relied upon the same delegates and value objects as the main application. This approach allowed me to focus on constructing our backend while another team member built out the user interface. We then had a way of detecting any changes in our complex api and adapting quickly. The approach helped us quite a bit and made me a believer.

For more information on the ideas behind unit testing the AsUnit site is a good start, Wikipedia has good definitions of terms, the Extreme Programming site has some good info, or maybe even check out A Guide to Testing the Rails in the Ruby on Rails Manual.

On my current project, I’m using Flash CS3 to write an ActionScript 3 application without using any Flex. It’s important that your testing framework mimic the rest of your application, so I decided to use the asunit framework instead of flexunit. I think asunit is fantastic, however I found that the documentation for as3 is a bit lacking. The best tutorial I found was by Tim Beynart on the FlashCodersNY blog, however it was for as2 and didn’t quite work for me out of the box. So I hacked at it a bit until I got it all to work. It turned out to be pretty straightforward. I offer here an update to Tim Beynart’s original tutorial which should work for Flash as3 applications.

1) Create a directory called AsUnitExample. Download the asunit framework zip file from sourceforge and copy the contents of the as3 directory into your AsUnitExample directory. All of the files we create in the following example will be in the root directory AsUnitExample. At this point the AsUnitExample directory should contain the file AsUnitTestRunner.as and the directories asunit and mx.

2) Open and inspect the file AsUnitExample/AsUnitTestRunner.as. It should contain the following

package {
    import asunit.textui.TestRunner;

    public class AsUnitTestRunner extends TestRunner {

        public function AsUnitTestRunner() {
            start(AllTests, null, TestRunner.SHOW_TRACE);
        }
    }
}

3) Create an .fla file to serve as the test container. In the Flash IDE, File->New->Flash File (Actionscript 3). Save the file as AsUnitExample/AsUnitTestRunner.fla. In the properties window, set the Document class in the properties to be AsUnitTestRunner. Save the file again. This .fla file will remain completely empty except for the link to the Document class. Using the Document class is new for Flash CS3 and replaces the approach of using a static main method as offered in Tim Beynart’s example. We’re doing this to avoid the error

TypeError: Error #1009: Cannot access a property or method of a null object reference. at asunit.textui::TestRunner/asunit.textui:TestRunner::addedHandler()

. The Adobe Design Center has an article titled Migrating for Flash 8 to Flash CS3 which explains the use of the Document class.

4) Create a sample class for us to run tests on. In the Flash IDE, File->New->ActionScript File. Save the file as AsUnitExample/Example.as. Paste in the following:

package {

    public class Example {

        public function add(num1:Number,num2:Number):Number{
            return num1 + num2;
        }
    }
}

5) Create a test for our sample class. Note that a single test class can contain multiple tests. They all share the same setUp and tearDown methods, which are called once for each test. In the Flash IDE, File->New->ActionScript File. Save the file as AsUnitExample/ExampleTest.as. Paste in the following:

package {
    import asunit.framework.TestCase;

    public class ExampleTest extends TestCase {

        private var _instance:Example;

        /**
         * Constructor
         *
         * @param testMethod Name of the method to test
         */
        public function ExampleTest(testMethod:String) {
            super(testMethod);
        }

        /**
         * Prepare for test, create instance of class that we are testing.
         * Invoked by TestCase.runMethod function.
         */
        protected override function setUp():void {
            _instance = new Example();
        }

        /**
         * Clean up after test, delete instance of class that we were testing.
         */
        protected override function tearDown():void {
            _instance = null;
        }

        /**
         * Test of whether or not class properly instantiated
         */
        public function testInstantiated():void {
            assertTrue("Example instantiated", _instance is Example);
        }

        /**
         * Test that is born to lose.
         */
        public function testFail():void {
            assertFalse("failing test", true);
        }

        /**
         * Test the addition method on example
         */
        public function testAddition():void {
            var result:Number = _instance.add(2,3);
            assertEquals("Expected:5 Received:"+result, result, 5);
        }
    }
}

6) Create the test suite. The AsUnit convention is that this class should be called AllTests and should reference each test that you want to run with an addTest call. Note that the parameter in the addTest call is the test class constructor using the test method name as an arguement. In the Flash IDE, File->New->ActionScript File. Save the file as AsUnitExample/AllTests.as. Paste in the following:

package {
    import asunit.framework.TestSuite;

    public class AllTests extends TestSuite {

        public function AllTests() {
            super();
            addTest(new ExampleTest("testInstantiated"));
            addTest(new ExampleTest("testAddition"));
            //addTest(new ExampleTest("testFail"));
        }
    }
}

7) In the Flash IDE, compile AsUnitTestRunner.fla by running Control->Test Movie. You should see the following:

AsUnit Success

8 ) In the file AsUnitExample/AllTests.as uncomment the line

addTest(new ExampleTest("testFail"));

and recompile the movie. This line runs a test which will always fail and you should see the following:

AsUnit Failure

And you are up and running. In the directory AsUnitExample/asunit/framework there are a bunch of examples which demonstrate how to write different types of tests. Nothing I’ve added here is too sophisticated, maybe future releases of asunit could contain these extra files? Just a thought.

I have used AsUnit to build a series of asynchronous tests for my Xml Rest service. Look for a follow up post demonstrating my use of AsUnit to build those services. If you have any trouble with these examples, please leave a comment and I’ll try to help.

21 comments ↓

#1 Evan on 09.21.07 at 6:07 pm

Brilliant. I tried it and it worked. Building applications in this way can only help to move Flash development into the “real” programming world.

Thanks for the tutorial

#2 Geddesign on 10.19.07 at 2:52 am

Thanks a million! This worked great. I put together a “Project Template” set of folders using this, so I can quickly create new projects that are ready to go. Using unit testing is the best way to program. It is hard to convince some people that doing more work (unit testing) will really save tons of time, but its true. Thanks again.
If any one wants a Project Template let me know.

#3 Livia T on 10.19.07 at 9:39 am

excellent, thank you! It worked from the first time :)

#4 Fred on 10.30.07 at 4:21 pm

Nice tool, but this works fines only for synchronous methods. How can i test asynchronous methods . For example i got a SOAP Service :
service = new NetConnection();
service.objectEncoding = ObjectEncoding.AMF0;
service.connect(WebConfig.GATEWAY_URL);
var responder:Responder = new Responder(HandleFindAllProjects, HandleRemotingError);
service.call(“ProjectService.FindAllProjects”, responder);
service.close();

How can i test the result of HandleFindAllProjects Method ?

#5 WS-Blog » AsUnit (AS3): RemoteTestCase for testing asynchronous data using Flash Remoting on 11.29.07 at 3:09 pm

[…] [AS3] Jonathan Marston: asunit testing with flash cs3 and actionscript 3 […]

#6 sectore on 11.29.07 at 3:23 pm

@Jonathan, great tutorial, thx for sharing all information!

@Fred: For asynchronous testing check out the AsynchronousTestCaseExample within the AsUnit Framework. For testing asynchronous data based on Flash Remoting check out the latest blog entry on WS-Blog, too http://www.websector.de/blog/2007/11/29/asunit-as3-remotetestcase-for-testing-asynchronous-data-using-flash-remoting/

;-)

-sectore

http://www.websector.de/blog/

#7 Tim Beynart on 12.12.07 at 4:39 pm

I am now using your tutorial to get ASUnit going with AS3. High fives all around.

#8 Sunil Gupta on 02.16.08 at 11:37 am

I tried this and it worked for me. It was really nice tutorial. Thanks for posting.

#9 Unit Testing in ActionScript 3.0! « Java vs C# on 03.06.08 at 3:54 pm

[…] Tutorial […]

#10 Brian Vaughn on 03.09.08 at 10:33 pm

Very nice! :)

You may also be interested in checking out the unit testing framework I’ve recently begun called “Reflex Unit”. It’s available on Google Code:
http://code.google.com/p/reflex-unit/

#11 Francois Savard on 07.23.08 at 6:08 pm

Nice tutorial, helped me get started quickly.

I explored a bit further concerning the addTest(…) syntax, and it seems you can simply write addTest(new MyTestCaseClass()), with no argument to your test case constructor. Using reflection (flash.utils.describeType, etc.), the TestCase parent class constructor (for AS3, at least) will automatically discover your “test…” methods.

That way you don’t need to manually add them for every new test function you write.

(I didn’t find this in the documentation, that’s why I post it here)

#12 Ranjeet Kumar on 10.20.08 at 5:08 am

How to write a test case for the function which is based on XML file?

#13 Gurpreet Singh on 12.02.08 at 7:06 am

Thanks for posting such a useful tutorial. I tried it and it’s really helpful.

#14 Martin Legris on 01.28.09 at 4:59 pm

thank you!! very helpful!

#15 van on 02.16.09 at 3:05 am

can this also be applicable to flash cs4?
thanks!

#16 Links: Unit Testing and Continous Integration with Flex and AsUnit « Fiji Ecuador Seattle Greece Montana on 04.22.09 at 1:32 pm

[…] A flash-oriented tutorial, but with good AsUnit explanations: http://www.marstonstudio.com/2007/07/28/asunit-testing-with-flash-cs3-and-actionscript-3/ […]

#17 Action Developers (RIA)» Arquivo do Blog » Teste de unidade para ActionScript com ASUnit on 05.14.09 at 11:31 pm

[…] de teste com o ASUnit, existem bons materiais ensinado como utiliza-lo disponĂ­veis em InsideRIA e Marston Development Studio, mas caso alguĂ©m sinta necessidade poderei apresentar um exemplo […]

#18 mark miles on 11.06.09 at 2:30 am

Is it allowed to have trace statements in test functions? I have tried hard looking for ways to do this without modifying ASUnit classes, but I failed. I need traces to check if my test functions are performing properly.

#19 Shailesh Mewada on 08.05.10 at 8:48 am

Very helpful!!!

#20 Sarah R on 10.05.10 at 1:41 pm

Very good tutorial! This was exactly what I’ve been searching for. Thanks!

#21 Actionscript Unit Testing on 05.04.13 at 10:56 am

[…] many of the "classes" are only defined as linkages from the main monster fla. I followed??ASUnit Tutorial and got it to work with their simple examples. But when I went to test a factory and child class I […]