FlexUnit + ANT + AIR
I'm a big fan of Unit Testing and Continuous Integration. Peter Martin blogged about how to achieve this for Flex. Basically, he created an Ant task that starts a server socket connection and forks a browser that launches a flexunit based application. The application opens a client socket connection back to the server and streams the flexunit results in JUnit XML format. The server reads the xml stream and writes it on the local disk.
Notice that all of this is done so that a flex application in a browser can write to the local disk. Pretty clever, but this is where AIR makes life a bit easier. A Flex application using AIR can write to a local disk drive. Since the source code of JUnitTestRunner was available (thanks Peter), I was able to 1) learn something and 2) adjust the
Next, was to compile the application in Ant as part of the CI process. Here is the target that calls mxmlc:
The last task in the target copies the application configuration to the build directory. I have modified the configuration file with the following entry:
Now to run the application - I admit that I cheated here a bit :-( where, rather than creating a "real" AIR application with it full signature and having to "allow" it to run everytime as it has been changed during the compilation, I use the adl executable as follows:
I've created a project that contains a
Notice that all of this is done so that a flex application in a browser can write to the local disk. Pretty clever, but this is where AIR makes life a bit easier. A Flex application using AIR can write to a local disk drive. Since the source code of JUnitTestRunner was available (thanks Peter), I was able to 1) learn something and 2) adjust the
sendResults function to write the result to disk.
private function sendResults() : void
{
for each (var report : Object in reports)
{
var xml : XML = createXMLReport(report);
var utf : String = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml.toString();
var file : File = new File();
if( m_basedir )
{
file = file.resolvePath( m_basedir + "/target/TEST-" + xml.@name + ".xml");
}
else
{
file = File.userDirectory.resolvePath("TEST-" + xml.@name + ".xml");
}
var fs : FileStream = new FileStream();
fs.open(file, FileMode.WRITE);
fs.writeUTFBytes(utf);
fs.close();
}
}
Next, was to compile the application in Ant as part of the CI process. Here is the target that calls mxmlc:
<target name="compile">
<java jar="${flex.home}/lib/mxmlc.jar" fork="true" failonerror="true" maxmemory="256m">
<jvmarg value="-Dapplication.home=${flex.home}"/>
<jvmarg value="-Dsun.io.useCanonCaches=false"/>
<arg line="-compiler.headless-server"/>
<arg line="-library-path+='libs/flexunit.swc'"/>
<arg line="-output='target/junitair.swf'"/>
<arg line="+configname=air"/>
<arg line="src/junitair.mxml"/>
</java>
<copy file="src/junitair-app.xml" todir="target"/>
</target>
The last task in the target copies the application configuration to the build directory. I have modified the configuration file with the following entry:
<content>junitair.swf</content>
Now to run the application - I admit that I cheated here a bit :-( where, rather than creating a "real" AIR application with it full signature and having to "allow" it to run everytime as it has been changed during the compilation, I use the adl executable as follows:
<target name="run">
<exec executable="adl" failonerror="true">
<arg value="target/junitair-app.xml"/>
<arg value="--"/>
<arg value="${basedir}"/>
</exec>
</target>
I've created a project that contains a
build.xml and the junitair.mxml application. Make sure to download the flex sdk. Create an environment variable FLEX_HOME that points to where you installed the sdk, and make sure that $FLEX_HOME/bin is in your path so that adl can be execute.
Comments
<target name="run">
<exec executable="${flex.home}/bin/adl" failonerror="false" osfamily="mac">
<arg value="target/testair-app.xml"/>
<arg value="--"/>
<arg value="${basedir}"/>
</exec>
<exec executable="${flex.home}/bin/adl.exe" failonerror="false" osfamily="winnt">
<arg value="target/testair-app.xml"/>
<arg value="--"/>
<arg value="${basedir}"/>
</exec>
<junitreport todir="target">
<fileset dir="target">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="${report.dir}"/>
</junitreport>
</target>
This removes the requirement of using the AIR libraries in your test runner, and seems like a more streamlined way to do it. Hope it helps someone else.