Run Flex Unit Tests from ANT
If you have any troubles understanding this post, make sure to revisit some of the older in this series as I assume you already have your build file and properties file set up.

This magic behind this is brought to you from the good guys at FlexUnit.org. They have made it possible to have the Flex (or AS3) Tester App output information to the FlexUnitTask.jar through a CIListener to be output to pretty little report files that can be read from ANT or humans.
This is not a post on how to write a unit test, best practices on unit tests, or how to set up FlexUnit with your project, I am going to assume you already understand that part.
With other languages running Unit Tests is relatively straight forward. You write your test, you run your test. What makes running Unit Tests more difficult in the Flash Player is the runtime environment. To actually run your tests you need to start up the Flash Player runtime environment and run within the Flash Player. Which means you have to compile you code, run it in Flash Player, and then output the results somewhere that they can be read by ANT to give you the results. Not an easy task, but that is what we are going to cover.
So first, you have your separate FlexUnit Project.
This project runs the FlexUnit Test Runner to run the Unit Tests that you’ve created for your code.
This particular application have intentional faults so that you can see both success and fault responses. Typically you would work to have no failed tests.
I make this a completely separate project from my main application specifically because I want to keep my main application as clean from clutter and additional code as possible. Can you combine the two? Yes. Do I? No. You may think that having the second application wouldn’t add much clutter, but I personally feel when you are dealing with Enterprise applications – and therefore many developers – the more simplistic that you can make your code base the better. With many developers – each of different skill levels – you don’t want to overload some developers that might have a harder time understanding the full set of code and tests and everything else. On top of that, you can have your bug testers work with an application without getting the ability to hurt your core application code. Again, the separation of code and duties will help you scale.
You can hit View Source and see the unit tests that I have created and also get an ANT build file to run just the FlexUnit Project in ANT.
Our Next Steps
If you have started this series from the beginning our ANT file currently builds the library, builds the application into a deploy folder, copies the non-embedded assets into the deploy folder, builds our html-wrappers into the deploy folder, and also builds our ASDocs from our library and also our application into an asdoc folder.
Now we are going to add the following steps into the build.
- Clean and create a test folder to hold the built test application
- Clean and create a report directory to hold your flexunit reports
- Compile the test runner application
- Execute the test runner application
- Generate the readable reports from the test
- Clean up (destroy) the test folder and the compiled test runner application
The first two parts are simple, we’ve done it multiple times already.
Added into your build file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <target name="cleanFlexUnitReport" description="Cleans the Report file"> <echo>Deleting FlexUnit Report Directory...</echo> <delete dir="${FlexUnitReport.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted FlexUnit Report Directory</echo> <echo>Creating FlexUnit Report Directory...</echo> <mkdir dir="${FlexUnitReport.dir}" /> <echo>Created FlexUnit Report Directory</echo> </target> <target name="cleanTest" description="Cleans the Test file"> <echo>Deleting Test Directory...</echo> <delete dir="${Test.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted Test Directory</echo> <echo>Creating Test Directory...</echo> <mkdir dir="${Test.dir}" /> <echo>Created Test Directory</echo> </target> |
Added into your properties file.
1 2 3 4 | #report output file FlexUnitReport.dir=${basedir}/flexUnitReport #test dir Test.dir=${basedir}/test |
Compile The Test Runner Application
Now we have the the folders necessary to hold all of our output, now we need to compile the test runner application. This part is going to be very similar to building the application because we will again be using functionality provided to us by flexTasks.jar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <target name="compileTestRunner"> <echo>Compiling Test Runner SWF To Test</echo> <mxmlc file="${TestRunnerSrc.dir}/${TestRunner.name}.mxml" output="${Test.dir}/${TestRunner.name}.swf"> <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/> <compiler.source-path path-element="${Src.dir}" /> <compiler.library-path dir="${basedir}/" append="true"> <include name="${DeploySWC.dir}"/> </compiler.library-path> <compiler.library-path dir="${TestRunnerLib.dir}" append="true"> <include name="*.swc"/> </compiler.library-path> <compiler.verbose-stacktraces>true</compiler.verbose-stacktraces> <compiler.headless-server>true</compiler.headless-server> </mxmlc> <echo>Compiled Test Runner SWF To Test</echo> </target> |
Here we set up the task and compile the project with any required libraries from the unit test project along with any libraries from our main application – so all dependencies are included, and the source code from the unit test project – our actual tests. The swf output from this compile task is placed into our test folder which later will be destroyed after it is no longer needed.
Here are the build properties added because of this task.
1 2 3 4 5 6 | #Test Runner Dir TestRunner.dir=C:/workspace/AntBuildUnitTest TestRunnerSrc.dir=${TestRunner.dir}/src TestRunnerLib.dir=${TestRunner.dir}/libs #Test Runner Dir TestRunner.name=ANTBuildUnitTest |
Executing The Test Runner
For this next part we need to add some additional capabilities to our ANT build file via the flexUnitTasks jar.
We will accomplish this addition the same way we added in the flexTasks.jar in the beginning. At the top of our build file, under the flexTasks.jar taskdef tag, add:
1 | <taskdef resource="flexUnitTasks.tasks" classpath="${FlexUnitTasks.file}"/> |
And in your properties just include the path to the file.
1 2 | #flextasks jar location FlexUnitTasks.file=flexTasks/flexUnitTasks-4.0.0.jar |
Now with the flexUnitTasks jar added to our build file, we can use the flexunit task. This task allows us to run the compiled test runner application and output the results to a folder of our choice.
Once you have the generated output, you can use the the compatible (and built in) junitreport task to create nice to read xml reports.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <target name="executeTestRunner" description="executes the test runner app"> <echo>Running Test Runner SWF</echo> <flexunit swf="${Test.dir}/${TestRunner.name}.swf" toDir="${FlexUnitReport.dir}" haltonfailure="false" verbose="true" localTrusted="true"/> <echo>Ran Test Runner SWF</echo> <echo>Generate Readable Tests</echo> <junitreport todir="${FlexUnitReport.dir}"> <fileset dir="${FlexUnitReport.dir}"> <include name="TEST-*.xml"/> </fileset> <report format="frames" todir="${FlexUnitReport.dir}/html"/> </junitreport> <echo>Generated Readable Tests</echo> </target> |
One thing I want to point out is the haltonfailure option. I set mine to false so that the build script keeps running, but you can also set this to true so that the build script fails immediately if an error in your unit tests come up. Dependent on your situation, this would be the only flag you may want to change.
Current File
There is only one more major task left to really make build file complete, automated testing, the brother of unit testing – a little bit different, equally important.
Currently your build script should look similar to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | <?xml version="1.0" encoding="UTF-8"?> <project name="Build File" basedir="." default="compileProject"> <!-- Set Up ================================================= --> <!-- file description --> <description>Build Script</description> <!--location of property file --> <property file="./build.properties" description="properities for builds" /> <!-- timestamp --> <tstamp> <format property="timestamp" pattern="yyyyMMdd" /> </tstamp> <!-- additional tasks --> <taskdef resource="flexTasks.tasks" classpath="${FlexTasks.file}"/> <taskdef resource="flexUnitTasks.tasks" classpath="${FlexUnitTasks.file}"/> <!-- ======================================================== --> <!-- Compile Project ======================================== --> <target name="compileProject" depends="cleanDeploy,buildWrapper,buildCustomWrapper,copyNonEmbeddedFiles,compileLibraries,runFlexUnitTests,compileApplication,asDocs,cleanTempDirectories,zipApplication" description="compiles application"/> <!-- Build Wrappers ========================================= --> <target name="buildWrapper"> <echo>Building Wrapper...</echo> <html-wrapper title="${Application.name}" height="100%" width="100%" bgcolor="#FFFFFF" file="${Application.name}.html" application="${Application.name}" swf="${Application.name}${timestamp}" version-major="${Major.version}" version-minor="${Minor.version}" version-revision="${Revision.version}" history="true" template="express-installation" output="${Deploy.dir}" /> <echo>Built Wrapper</echo> </target> <target name="buildCustomWrapper"> <echo>Building Custom Wrapper...</echo> <copy file="${Template.file}" tofile="${Deploy.dir}/${Output.file}" overwrite="true"> <filterchain> <replacetokens> <token key="version_major" value="${Major.version}"/> <token key="version_minor" value="${Minor.version}"/> <token key="version_revision" value="${Revision.version}"/> <token key="application" value="${Application.name}"/> <token key="width" value="100%"/> <token key="height" value="100%"/> <token key="bgcolor" value="#FFFFFF"/> <token key="swf" value="${Application.name}${timestamp}"/> </replacetokens> </filterchain> </copy> <echo>Built Custom Wrapper</echo> </target> <!-- ======================================================== --> <!-- Compile Application ==================================== --> <target name="compileApplication"> <echo>Compiling SWF To Deploy</echo> <mxmlc file="${Src.dir}/${Application.name}.mxml" incremental="false" actionscript-file-encoding="UTF-8" output="${Deploy.dir}/${Application.name}${timestamp}.swf" debug="${Debug.Boolean}" keep-generated-actionscript="false"> <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/> <default-background-color>0xFFFFFF</default-background-color> <metadata> <creator>Jonathan Campos</creator> <publisher>UnitedMindset</publisher> <language>EN</language> </metadata> <compiler.source-path path-element="${Src.dir}" /> <compiler.library-path dir="${basedir}/${DeploySWC.dir}" append="true"> <include name="*.swc"/> </compiler.library-path> </mxmlc> <echo>Compiled SWF To Deploy</echo> </target> <!-- ======================================================== --> <!-- NONEMBEDDED FILES ====================================== --> <target name="copyNonEmbeddedFiles"> <echo>Deleting Deploy Assets Directory...</echo> <delete dir="${DeployAssets.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted Deploy Assets Directory</echo> <echo>Creating Assets Folder</echo> <mkdir dir="${DeployAssets.dir}"/> <echo>Created Assets Folder</echo> <echo>Copy Nonembedded Resources To Deploy</echo> <copy todir="${DeployAssets.dir}" includeemptydirs="false" overwrite="true"> <fileset dir="${Assets.dir}"/> </copy> <echo>Copied Nonembedded Resources To Deploy</echo> </target> <!-- ======================================================== --> <!-- COMPILE LIBRARIES ====================================== --> <target name="compileLibraries" depends="cleanDeploySWCs,copyPrecompiledSWCs,compileLibrary" /> <target name="cleanDeploySWCs"> <echo>Deleting Deploy SWC Directory...</echo> <delete dir="${DeploySWC.dir}" failOnError="false" includeEmptyDirs="true"/> <echo>Deleted Deploy SWC Directory</echo> <echo>Creating Deploy SWC Directory...</echo> <mkdir dir="${DeploySWC.dir}"/> <echo>Created Deploy SWC Directory</echo> </target> <target name="copyPrecompiledSWCs"> <echo>Copying to Deploy SWC Directory...</echo> <copy todir="${DeploySWC.dir}" includeemptydirs="false" overwrite="true"> <fileset dir="${ApplicationLibs.dir}"/> </copy> <echo>Copied to Deploy SWC Directory...</echo> </target> <target name="compileLibrary" description="compiles the Library"> <echo>Compiling Library SWC To Deploy SWC Folder</echo> <compc debug="${Debug.Boolean}" output="${DeploySWC.dir}/${Library.name}.swc"> <source-path path-element="${LibrarySrc.dir}"/> <include-sources dir="${LibrarySrc.dir}" includes="*"/> <compiler.library-path dir="${LibraryLibs.dir}" append="true"> <include name="*.swc"/> </compiler.library-path> <metadata> <creator>Jonathan Campos</creator> <publisher>UnitedMindset</publisher> <language>EN</language> </metadata> </compc> <echo>Compiled Library SWC To Deploy SWC Folder</echo> </target> <!-- Clean Up =============================================== --> <target name="cleanDeploy" description="Cleans the deploy file"> <echo>Deleting Deploy Directory...</echo> <delete dir="${Deploy.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted Deploy Directory</echo> <echo>Creating Deploy Directory...</echo> <mkdir dir="${Deploy.dir}" /> <echo>Created Deploy Directory</echo> </target> <target name="cleanTempDirectories"> <echo>Deleting Deploy SWC Directory...</echo> <delete dir="${DeploySWC.dir}" failOnError="false" includeEmptyDirs="true"/> <echo>Deleted Deploy SWC Directory</echo> <echo>Deleting Test Directory...</echo> <delete dir="${Test.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted Test Directory</echo> </target> <!-- ======================================================== --> <!-- ASDOC ================================================== --> <target name="asDocs" depends="cleanASDoc,compileASDoc" description="build of asdocs" /> <!-- Delete the existing output folder and files and then regenerate the output folder --> <target name="cleanASDoc"> <echo>Deleting ASDoc Directory...</echo> <delete dir="${Asdoc.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted ASDoc Directory</echo> <echo>Creating ASDoc Directory...</echo> <mkdir dir="${Asdoc.dir}" /> <echo>Created ASDoc Directory</echo> </target> <!-- Run the ASDoc executable and generate the ASDocs to the new output folder --> <target name="compileASDoc"> <echo>ASDoc Compiling...</echo> <exec executable="${AsDocs.executable}" failonerror="true"> <arg line="-doc-sources '${AppClasses.dir}'" /> <arg line="-doc-sources '${LibrarySrc.dir}'" /> <arg line="-external-library-path '${LibrarySrc.dir}'" /> <arg line="-external-library-path '${Library.dir}/${LibraryLibs.dir}'" /> <arg line="-main-title '${Main.title}'" /> <arg line="-window-title '${Window.title}'" /> <arg line="-output '${Asdoc.dir}'" /> <arg line="-footer '${Footer.text}'" /> </exec> <echo>ASDoc Compile Complete</echo> </target> <!-- ======================================================== --> <!-- FlexUnit =============================================== --> <target name="runFlexUnitTests" description="run flexunit tests" depends="cleanFlexUnitReport,cleanTest,compileTestRunner,executeTestRunner"/> <target name="cleanFlexUnitReport" description="Cleans the Report file"> <echo>Deleting FlexUnit Report Directory...</echo> <delete dir="${FlexUnitReport.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted FlexUnit Report Directory</echo> <echo>Creating FlexUnit Report Directory...</echo> <mkdir dir="${FlexUnitReport.dir}" /> <echo>Created FlexUnit Report Directory</echo> </target> <target name="cleanTest" description="Cleans the Test file"> <echo>Deleting Test Directory...</echo> <delete dir="${Test.dir}" failOnError="false" includeEmptyDirs="true" /> <echo>Deleted Test Directory</echo> <echo>Creating Test Directory...</echo> <mkdir dir="${Test.dir}" /> <echo>Created Test Directory</echo> </target> <target name="compileTestRunner"> <echo>Compiling Test Runner SWF To Test</echo> <mxmlc file="${TestRunnerSrc.dir}/${TestRunner.name}.mxml" output="${Test.dir}/${TestRunner.name}.swf"> <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/> <compiler.source-path path-element="${Src.dir}" /> <compiler.library-path dir="${basedir}/" append="true"> <include name="${DeploySWC.dir}"/> </compiler.library-path> <compiler.library-path dir="${TestRunnerLib.dir}" append="true"> <include name="*.swc"/> </compiler.library-path> <compiler.verbose-stacktraces>true</compiler.verbose-stacktraces> <compiler.headless-server>true</compiler.headless-server> </mxmlc> <echo>Compiled Test Runner SWF To Test</echo> </target> <target name="executeTestRunner" description="executes the test runner app"> <echo>Running Test Runner SWF</echo> <flexunit swf="${Test.dir}/${TestRunner.name}.swf" toDir="${FlexUnitReport.dir}" haltonfailure="false" verbose="true" localTrusted="true"/> <echo>Ran Test Runner SWF</echo> <echo>Generate Readable Tests</echo> <junitreport todir="${FlexUnitReport.dir}"> <fileset dir="${FlexUnitReport.dir}"> <include name="TEST-*.xml"/> </fileset> <report format="frames" todir="${FlexUnitReport.dir}/html"/> </junitreport> <echo>Generated Readable Tests</echo> </target> <!-- ======================================================== --> </project> |
And your properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ##################################################################### # # Compiler Properties # ##################################################################### # Flex SDK File Location FLEX_HOME=C:/Program Files/Adobe/Flex Builder 3 Plug-in/sdks/3.3 #flextasks jar location FlexTasks.file=flexTasks/flexTasks.jar #deploy directory Deploy.dir=deploy #source directory Src.dir=src #debug flag Debug.Boolean=false #application name Application.name=ANTBuildProject #version major Major.version=9 #version minor Minor.version=0 #version revision Revision.version=124 #Template File Template.file=index.template.html #Output HTML File Output.file=index.html #Assets Assets.dir=${Src.dir}/assets #Assets DeployAssets.dir=${Deploy.dir}/assets #Deploy SWC Directory DeploySWC.dir=deploySWC #Library Directory Library.dir=C:/workspace/ANTBuildLibrary #Library Libs LibraryLibs.dir=${Library.dir}/libs #Library Src LibrarySrc.dir=${Library.dir}/src #library name Library.name=ANTBuildLibrary #Application Libs ApplicationLibs.dir=${basedir}/libs ##################################################################### # # ASDoc Properties # ##################################################################### #asdoc output Asdoc.dir=asdoc #the location of asdocs on your computer AsDocs.executable=${FLEX_HOME}/bin/asdoc.exe #Asdoc Footer Text Footer.text=Some legal jargon #window title Window.title=Window Title #main title Main.title=Main Title #the location of your application classes on your computer AppClasses.dir=${basedir}/src ##################################################################### # # FlexUnit Properties # ##################################################################### #report output file FlexUnitReport.dir=${basedir}/flexUnitReport #test dir Test.dir=${basedir}/test #flextasks jar location FlexUnitTasks.file=flexTasks/flexUnitTasks-4.0.0.jar #Test Runner Dir TestRunner.dir=C:/workspace/AntBuildUnitTest TestRunnerSrc.dir=${TestRunner.dir}/src TestRunnerLib.dir=${TestRunner.dir}/libs #Test Runner Dir TestRunner.name=ANTBuildUnitTest |
You’ll notice the one place I didn’t spend time showing the changes is the main targets, including the compileProject target. As I add functionality I automatically write in this functionality to the main compileProject target and make up unique subtarget. How you set up your file and it’s parts is up to you.





[...] FlexUnit tests I am going to assume a few things: 1) You already have a working understanding of FlexMonkey. 2) [...]
I’ve been reading your ANT posts so far and they have been a great help in learning ANT and to make my iteration deployment easier. Thanks.
I ran into one problem with trying to generate my FlexUnit report using your example.
I downloaded your example and just changed some paths in the properties file for my machine and everything seems to work fine, except the TESTS-TestSuites.xml is empty. The XML files for the unit tests have information, just not the suite, so the report has 0′s for all results.
I tried it at work and at home, and even on a simple project from scratch. Not sure if I’m missing something.
Thanks, your articles have been a big help so far.
Well that’s not good. That means I put up the files from an older build that I had that same issue. I would double check your “Generate Readable Tests” and look at the section. Make sure it is When originally putting this together I accidentally put an ‘s’ on the end of TEST and that causes issues. Sorry for that. Try removing that and let me know how it goes.
That was it! Works perfectly now. Thanks. Nice work on the series.
Thank you so much! My build.xml works at last.