Unit testing isn't a particularly common practice among Flash developers. Perhaps that's because so many of us are self-taught and not aware of what goes on in other languages, or perhaps it's because, until recently, many Flash-based projects were relatively small-scale.
In this article, I am going to deal with the how and what, but not necessarily the why for Test Driven Development for ActionScript 3.0 and Flex 2. If you want to know 'why', a simple Google search will return a plethora of resources.
I'll do my best to collate and share what I have discovered over this period and show you how to unit-test using FlexUnit, hopefully saving you from some of the frustration and head-scratching I experienced.
flexunit .zip (ZIP, 1.8 MB)
Object-oriented programming (OOP), and some ActionScript 2.0 (enough to understand ActionScript 3.0.)
Test Driven Development is one of the rules of eXtreme Programming (XP).
Originally, XP programmers wrote tests for any part of their code that could break. However, this soon evolved in to the practice of writing the tests before writing the actual code. This may sound strange, but there is reason behind this madness; by knowing what can go wrong, you have a better idea of what your code needs to be able to handle.
TDD has evolved in to a process by which code is generated, as opposed to a testing process. It does still effectively perform tests, but that is more of a by-product.
The first thing you need is a Unit Testing framework. You can write your own, but that is not necessary. Most people use one of the existing frameworks such as FlexUnit or ASUnit.
In TDD, functionality is added in very small chunks: You come up with a test, you write the test, you write the code to satisfy the test, possibly refactor it to make it more efficient, and then start with the next test. Each test may only take a minute or so to write; it may take 10; one test should not take hours though.
This quote, from Dave Astels gave me my first clear definition of TDD:
"It's about figuring out what you are trying to do before you run off half-cocked to try to do it. You write a specification that nails down a small aspect of behaviour in a concise, unambiguous, and executable form. It's that simple. Does that mean you write tests? No. It means you write specifications of what your code will have to do. It means you specify the behaviour of your code ahead of time. But not far ahead of time. In fact, just before you write the code is best because that's when you have as much information at hand as you will up to that point. Like well done TDD, you work in tiny increments... specifying one small aspect of behaviour at a time, then implementing it." – Dave Astels
There is in fact a kind of "testing dance" you perform, and it's known as the Test-Code-Simplify cycle:
The Test-Code-Simplify cycle (Quoted verbatim from "Extreme Programming Applied", p159):
I'm going to use FlexUnit for this tutorial. The "Flex" part may be a little misleading. You do need Flex in order to use it, but the framework can be used to test pure ActionScript 3.0 files as well.
Before looking at how to use FlexUnit, let's get familiar with some terminology. Bear with me—it's a bit of a chicken and egg situation, and will make more sense as you construct tests later on.
An assertion is a statement of expected outcome. In other words, it is the expected result of your test. You may assert that the sky should be blue, or that you want x to be equal to y. In TDD if your assertion turns out to be something other than what you expected, you write code to correct that in your class.
There may be some setup that is constant across all of your tests. For example, each test may depend on the creation of a certain object, property or process. A test fixture is useful if you have two or more tests for a common set of objects, as it avoids duplicating the code necessary to initialize and clean up the common objects. Methods called setUp() and tearDown() are provided for this common code, and any properties used can be declared at the top of the class.
A test case is the smallest unit of testing. It checks for a specific response to a particular set of inputs. Your test class must extend the TestCase class and have a constructor that calls the super class's constructor. In some frameworks, all test methods should begin with the word "test." So if you are testing that the beer is cold, your method will be called something like testBeerIsCold().
As more and more unit tests accumulate for a given project, you will want a way to group them. Running them one at a time would be cumbersome. A TestSuite can contain other TestSuites, or individual tests, and is a way of declaring which test must be run in the same session, regardless of whether or not they are in the same file. This way of aggregating tests is very handy as you'll soon see.
A test runner is a component that often has a graphical interface and displays the outcome of our tests. In FlexUnit you tell your TestRunner which TestSuite you want to use, and then call its startTest() method.
The class that extends TestCase may contain a test suite, will contain test cases and may possibly contain test fixtures. From what I can gather this class is referred to as a test harness, although usage of this term seems to vary in the documents I've looked at. Some documentation considers that the harness is the process that instantiates the runner and passes in the suites that you want to run, while Wikipedia defines a test harness as the an Automated Test Framework (ATF).
Congratulations if you managed to get through all that. It wasn't exactly exciting reading, but they are useful terms to refer back to as you look at the examples below.
Let's get on with installing FlexUnit and creating our tests...
Neil Webb is a Flash Platform Developer who has been very active in the Flash community for a number of years. Neil has worked with clients such as Cambridge University, FIFA and Hutchinson Whampoa.