<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Eyefodder</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/" />
    <link rel="self" type="application/atom+xml" href="http://www.eyefodder.com/blog/atom.xml" />
   <id>tag:www.eyefodder.com,2009:/blog//1</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1" title="Eyefodder" />
    <updated>2009-07-28T22:52:38Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>Code Coverage with Flex - a headless agent for CI builds</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2009/07/code_coverage_with_flex_a_head.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=43" title="Code Coverage with Flex - a headless agent for CI builds" />
    <id>tag:www.eyefodder.com,2009:/blog//1.43</id>
    
    <published>2009-07-28T22:29:37Z</published>
    <updated>2009-07-28T22:52:38Z</updated>
    
    <summary>In my last blog post I gave details of how I user the modified coverage viewer in an automated build to follow the trend of code coverage over time. The trouble with this approach was that there was a problem...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>In my last blog post I gave details of how I user the modified coverage viewer in an automated build to follow the trend of code coverage over time. The trouble with this approach was that there was a problem either with the localConnection or the code that uses it and there was a wide variance of the values being reported. This post shows you how I fixed it by creating a headless coverage reporter that you can drop into your test harness and remove the need for a second application altogether.</p>]]>
        <![CDATA[<p>In order to try and do this I decided to use as much of the code as possible that the FlexCover guys had written, and only change what I needed to get it working.Once I had it up and running I could worry about making it faster / leaner / more neatly coded...</p>

<h3>The approach</h3>
So here's the basic plan:
<ol>
<li>Swap out the default localConnection reporting mechanism for one that will pick and choose depending on environment the app is running in</li>
<li>Create a headless agent that will pull the coverage data collection and reporting side of the coverageViewer into the app</li>
<li>Use commandline options to swap between the headless agent and local connection agent</li>
<li>Default to using the localConnnection agent</li>
</ol>

<h3>How it works</h3>
When your app compiles using the instrumented SDK created for using FlexCover, your application makes use of a class called CoverageManager. This manager is a patch that allows you to plug in a custom coverage agent for use in your app. By default it uses a class called LocalConnectionCoverageAgent which broadcasts coverage metadata to the coverage viewer application. What my patch does is get in and allow you to use a different, headless agent. To do this simply call during the preinitialize event of your main application:

<pre>
private function injectAgent():void{
	CoverageManager.agent = new CoverageAgentSwitch();
}</pre>

<p>As a quick test, run your app as you had previously and confirm it still works by sending data over a localConnection to the CoverageViewer. This is expected as by default, the switch will create a LocalConnectionCoverageAgent. In order to use the headless agent you need to set a few commandline properties. First you need to tell the switch that you want to use the headless agent. Then the headless agent needs to know where it's getting its metadata from, where it should output the coverage report. The commandline options are:</p>

<p><code><br />
-coverage-agent-type=headless <i>Headless is only option, anything else will default to localConnectionAgent</i><br />
-coverage-metadata='/full/path/to/coverage/metadata.cvm'<br />
-coverage-output='/full/path/to/coverage/reportInOriginalFormat.cvr'<br />
-emma-report='/full/path/to/coverage/reportInEmmaFormat.xml'<br />
</code></p>

<p>Note that if you don't specify the metadata path and at least one of the report formats, the headless agent will log errors but otherwise fail silently.</p>

<p>In terms of the edits I made to get it working, that is pretty much it. The headlessCoverageAgent swc is probably larger than it needs to be and is definitely grossly inefficient. I will update this soon to improve this, but right now I only have time to get this post up. </p>

<p>Obviously you will have to change your buildscript to pass these new commandline parameters in to the testharness when you run it. If there is any interest, I'll post my updated build script and testharness modifications that dispense with the log parser altogether and make for a more repeatable build script.</p>

<h3>The Result</h3>
My build process is now much quicker because I don't have to wait to be sure that the coverage viewer has initialized. It's also completely stable and the coverage trend has been a great motivator for the team.

<p><img alt="coverageCIBad.gif" src="http://www.eyefodder.com/blog/images/betterCoverage.png" width="324" height="266" /><br />
<i>Coverage trend without crazy variance found using the external viewer</i></p>

<p><a href="http://www.eyefodder.com/blog/downloads/headlessCoverageAgent.swc.zip">Download headless agent library</a></p>]]>
    </content>
</entry>
<entry>
    <title>Code Coverage with Flex - ANT build for running the viewer</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2009/07/code_coverage_with_flex_runnin.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=42" title="Code Coverage with Flex - ANT build for running the viewer" />
    <id>tag:www.eyefodder.com,2009:/blog//1.42</id>
    
    <published>2009-07-26T00:47:08Z</published>
    <updated>2009-07-26T16:25:29Z</updated>
    
    <summary>In my last post, I gave you my elegant extension hack for generating EMMA style reports from FlexCover. This post covers the first route I took to incorporating this in my build process. It does work, but it&apos;s not very...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>In my last post, I gave you my <del>elegant extension</del> hack for generating <a href="http://emma.sourceforge.net/">EMMA</a> style reports from <a href="http://code.google.com/p/flexcover/">FlexCover</a>. This post covers the first route I took to incorporating this in my build process. It does work, but it's not very consistent in its reporting and I'll explain why at the end...</p>]]>
        <![CDATA[<p>So by now I had my Coverage Viewer happily spitting out EMMA formatted coverage reports that my build machine was just dying to consume. All I had to do was get the running of the coverage test and the outputting of the report to be an integral part of my build. Here is the sequence of events for my build process:</p>

<ol>
<li>clean my output folders (delete and recreate them)</li>
<li>Compile the main application using the instrumented SDK. This will generate the .cvr metadatafile that the coverageViewer needs</li>
<li>Compile the test harness using the instrumented SDK. This is so that when it runs, the hooks injected by the SDK report coverage data.</li>
<li>Launch the Coverage Viewer Application (specifying EMMA output file)</li>
<li>Run the test harness. When it is finished, call CoverageManager.exit() which will close the coverage viewer</li>
<li>Wait for the test results and coverage report to be available. By implication this means that the test harness and coverage viewer have quit.</li>
<li>Compile the main app using the standard SDK</li>
<li>(AIR Apps only) remove test harness and any test data from the output folder</li>
<li>(AIR Apps only) package up the application</li>
</ol>

<p>In theory this is all well and good. In practice there are a few problems:</p>

<p> * The coverage viewer has to launch and parse the coverage metadata file. There isnt a simple way to feed this back to the ant script, so you have to get the script to wait. I set mine to 30 seconds, which should be enough. Nevertheless, this sort of thing frankly just irks me - either at some point it will fail, and up until that point, the build is taking longer han it needs to.<br />
 <br />
 * There are two applications being launched by the build process. In order for this to work, you need to launch the coverageViewer with <code>spawn='true'</code> If something goes wrong with the build, the script no longer has control of this process (I might be wrong on this one - correct me if so..)<br />
 <br />
 * The coverage agent (that gets injected into our test harness by the instrumented SDK) and the coverage viewere communicate via LocalConnection. This allows two flash applications on the same machine to talk to one another. Unfortunately, LocalConnections can be kind of flaky and you have to build a separate local connection for each direction of communication. <br />
 <br />
 The first two I could live with, but when I put this together, I found that there was quite a wide variance of about 10% from build to build of coverage values:</p>

<p><img alt="coverageCIBad.gif" src="http://www.eyefodder.com/blog/images/coverageCIBad.gif" width="325" height="250" /><br />
<i>Coverage trend showing wide variance of reporting results</i><br />
<br/><br />
I was left with one of two conclusions:<br />
 <ol><br />
 <li>There was a bug/ fragility in the localConnection and it couldn't be relied on</li><br />
 <li>There was a bug in the coverageAgent.exit() code sequence</li><br />
 </ol><br />
 <br />
 The way CoverageAgent.exit() works is that you call it from within your application and it:<br />
 <ol><br />
 <li>Waits until the application has sent all remianing coverage data</li><br />
 <li>Sends a message to the coverage viewer asking it to prepare for exit</li><br />
 <li>The coverage viewer writes out any report files</li><br />
 <li>Exits, and sends a message back to the main application telling it to exit</li><br />
 </ol><br />
 Somewhere in this back and forth coverage data was getting lost, and occasionally the build was failing because the report file was not getting written. I could have attempted to debug the code, but in my experience, debugging LocalConnections is a royal ballache. In the end I decided to bring the reporting side of the coverage viewer 'in-house' and avoid the need for a second application altogether. My next post will show this and give you a download to the swc so that you can do it yourself...<br />
 <br />
 Just in case you are interested, I have attached the buildfile I used for running the coverageViewer application as part of the build. If you can wait till I post the next update to this, I'd suggest you do :)</p>

<p><a href="http://www.eyefodder.com/blog/downloads/coverageViewerANTBuild.zip">Download build file archive</a><br />
 <br />
 </p>]]>
    </content>
</entry>
<entry>
    <title>Code Coverage with Flex - creating EMMA formatted reports</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2009/07/flex_code_coverage_process_par.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=41" title="Code Coverage with Flex - creating EMMA formatted reports" />
    <id>tag:www.eyefodder.com,2009:/blog//1.41</id>
    
    <published>2009-07-24T20:16:58Z</published>
    <updated>2009-07-25T22:38:22Z</updated>
    
    <summary>Details on my hack for creating EMMA formatted code coverage reports using FlexUnit</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>Over the last few months I have adopted <a href="https://hudson.dev.java.net/">Hudson</a> as my build machine of choice as it is just so easy to setup and administer. Another thing I really like is being able to watch the trend of the number of tests in my test harness over time. It's not the best metric, but it does act as a reasonable motivator.</p>

<p>A slightly less crude metric is code coverage, which measures the amount of an application that gets exercised when it's run. <a href="http://code.google.com/p/flexcover/">FlexCover</a> is a very cool tool for this and props to my colleague - <a href="http://blogs.adobe.com/auhlmann/">Alex Uhlmann</a> and <a href="http://joeberkovitz.com/">Joe Berkowitz</a> of Allurent for the great work they've done. There is a great UI for exploring code coverage in detail and it can also export xml formatted reports on coverage.</p>

<p>The thing is, I want to be able to track this coverage over time in Hudson, just like I can with the number of tests. I achieved this by extending FlexCover to output <a href="http://emma.sourceforge.net/">EMMA</a> formatted reports...</p>]]>
        <![CDATA[<p>So as I was starting to look at this, I could see one of three paths: <br />
<ol><br />
<li>Create a Hudson plugin to consume flexCover's report format</li><br />
<li>Add some sort of XSLT transform to my build process</li><br />
<li>Modify FlexCover to be able to output a report format that Hudson understands</li><br />
</ol></p>

<p>Creating a plugin for Hudson certainly seemed like a possibility, but the plugins for EMMA and Cobertura were already there and stable, so it seemed like it would be much simpler to try and create a report in a format one of these plugins would understand. Creating an XSLT would work for this, but I'm not an XML guroid, so I figured I'd go down the route of the simplest thing that would work for me and <del>hack</del> extend flexcover to be able to output EMMA formatted reports.</p>

<p>As it turns out this was a pretty simple job, and after a few hours work I managed to create a patch that allows you to output .cvr or EMMA reports with an additional commandline argument. Alex, Joe and I have talked and although my way of doing it works, it is not designed to be scalable or modular to support more formats. They are incorporating the patch, but will probably rework it with these things in mind. They are super busy guys and it wont happen quickly; if you want to in the meantime you can grab the patch from here, but bear in mind it is offered with absolutely no warranties or support :)</p>

<h4>Installation</h4>
First thing you need to do is checkout the FlexCover code from Google code  (http://flexcover.googlecode.com/svn/trunk/CoverageViewer) and patch it with the file attatched. The patch is created from the 'com' level down. To do this, you can right click the file from within Eclipse and select 'Team>Apply Patch...' Follow the instructions and you should be good to go...

<h4>Usage</h4>
In order to write out the coverage report file with the coverage viewer, you need to supply the commandline argument:
<code>-output <i>/full/path/to/my/flexcoverreport.xml</i></code>
This functionality is unchanged, but now you can also specify an EMMA formatted file using the following:

<p><code>-emma-report <i>/full/path/to/my/EmmaReportName.xml</i></p>

<p>And that's about it! My next post covers the challenges I had integrating this into my build process, and how I overcame them...</p>

<p><a href="http://www.eyefodder.com/blog/downloads/emmaReportPatch.txt">Download patch file</a><br />
</p>]]>
    </content>
</entry>
<entry>
    <title>flexunit eclipse plugin alpha</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/08/flexunit_eclipse_plugin_alpha.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=40" title="flexunit eclipse plugin alpha" />
    <id>tag:www.eyefodder.com,2007:/blog//1.40</id>
    
    <published>2007-08-30T12:26:37Z</published>
    <updated>2007-08-30T15:40:11Z</updated>
    
    <summary>I&apos;ve been kind of quiet recently for three reasons: Its summer Work has been insanely busy I&apos;ve been beavering away on a new plugin for eclipse The plugin is designed with one key goal in mind: shortening the develop-test feedback...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>I've been kind of quiet recently for three reasons:<br />
<ul><br />
<li>Its summer</li><br />
<li>Work has been insanely busy</li><br />
<li>I've been beavering away on a new plugin for eclipse</li><br />
</ul><br />
The plugin is designed with one key goal in mind: shortening the develop-test feedback loop. It integrates eclipse and the flexunit framework to make our lives as developers easier.<br />
The plan is to release the plugin on <a href="http://labs.adobe.com/">labs</a> as soon as possible (I'm about to go on holiday for a couple of weeks so it'll be October at the earliest...) but I thought I'd give you an early heads-up on what I've been doing when its been too hot to walk the New York streets...</p>]]>
        <![CDATA[<p>So, here's what I've done so far:<br />
<ul><br />
<li>Modded the flexunit visual layout to work better in an IDE window</li><br />
<li>Setup the plugin to switch test runner when you switch between projects</li><br />
<li>Modded the flexunit swf to make it easier to re-run the test by clciking on the bar</li><br />
<li>Re-run the test when the test harness is recompiled</li><br />
<li>Set it up so that the developer can run a subset of tests</li><br />
<li>Set it up so that the test harness mxml is templated and can be distinct per project</li><br />
</ul></p>

<p>Plans for the future:<br />
<ul><br />
<li>integrate more tightly with CI build processes</li><br />
<li>autogenerate ANT build script</li><br />
<li>ability to choose tests on a per-method rather than per-test class basis</li><br />
<li>Incorporate other very cool stuff that flexunit has coming down the line</li><br />
</ul></p>

<p>So, for now we are planning to have an internal release; the plugin is definitely alpha and I'd like to keep it  to a limited group to iron out bugs, tighten up my bad Java and find out what a cross-section of our developers need. The plan is to release internally to Adobe Consulting, but if you are a forgiving and patient person who could really benefit from this, drop me a note and we can chat...<br />
</p>]]>
    </content>
</entry>
<entry>
    <title>Continuous Integration with Flex - a better log parser</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/06/continuous_integration_with_fl_7.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=38" title="Continuous Integration with Flex - a better log parser" />
    <id>tag:www.eyefodder.com,2007:/blog//1.38</id>
    
    <published>2007-06-13T15:01:34Z</published>
    <updated>2007-06-14T00:43:55Z</updated>
    
    <summary>About a year ago, I posted a six part series explaining how to set up a continuous integration process for your Flex projects. Since then I have been refining the process when I have had a spare moment. One of...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>About a year ago, I posted a six part series explaining how to set up a continuous integration process for your Flex projects. Since then I have been refining the process when I have had a spare moment. One of the hassles I found when trying to setup CI on a new machine was getting the python based flash log parser working. I decided to remove the python dependency altogether and create a jar that parses the flash logs.</p>]]>
        <![CDATA[<p>So, grab the <a href="http://www.eyefodder.com/blog/downloads/FlashLogParser.jar.zip">jar from here</a> and unzip it to your externals/lib directory. Then add the following properties to your build:<br />
<code><pre><br />
&lt;property name="logParser" value="${lib}/FlashLogParser.jar"/&gt;<br />
&lt;property name="flashStatus.location" value="${logs}/status.txt"/&gt;<br />
&lt;property name="flashOutput.location" value="${logs}/TEST-testOutput.xml"/&gt;<br />
</pre></code><br />
Then, change your parseFlashLog target to look like this:<br />
<code><pre><br />
&lt;target name="parseFlashLog" description="parses flash log" depends="clean" &gt;<br />
  &lt;java jar="${logParser}" failonerror="true" fork="true"&gt;<br />
  	&lt;arg line="'${flashlog.location}'"/&gt;<br />
  	&lt;arg line="'${flashStatus.location}'"/&gt;<br />
  	&lt;arg line="'${flashOutput.location}'"/&gt;<br />
  &lt;/java&gt;<br />
&lt;/target&gt;<br />
</pre></code><br />
Now you should be good to go...<br />
In my next post I am going to do a full dissection of my latest build file - I have spent some time refining it over the last year, and I think its probably helpful to spend some time looking at it bit by bit...</p>]]>
    </content>
</entry>
<entry>
    <title>CruiseControl on the Mac - modifying the build script to work x-platform</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/06/cruisecontrol_on_the_mac_modif.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=37" title="CruiseControl on the Mac - modifying the build script to work x-platform" />
    <id>tag:www.eyefodder.com,2007:/blog//1.37</id>
    
    <published>2007-06-12T21:10:22Z</published>
    <updated>2007-06-12T22:13:04Z</updated>
    
    <summary>So, I thought I was doing pretty well, getting svn working on the mac, installing cruisecontrol, even getting SCPlugin working with unsigned certificates. Then I tried to run my ant build, and ended up having all sorts of problems getting...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Continuous Integration" />
            <category term="FlexUnit" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>So, I thought I was doing pretty well, getting svn working on the mac, installing cruisecontrol, even getting SCPlugin working with unsigned certificates. Then I tried to run my ant build, and ended up having all sorts of problems getting my mac debug player to run. Some investigating and help from the ANT folks later, and I have a solution</p>]]>
        <![CDATA[<p>So, when I ran my ant build, all went well until the <code>runTest</code> target executed (or at least tried to execute). I got the following build error:<br />
<code><br />
Execute failed: java.io.IOException: debugPlayerMac.app cannot execute<br />
</code><br />
You see the problem is that on a mac, the standalone player (like other applications on the Mac) is actually a folder containing all sorts of cleverness inside. Ant doesn't know how to execute a folder, so I was a bit stuck. Until, after lots of digging, I found the answer in an old <a href="http://osflash.org/">osflash</a> mailing list <a href="http://readlist.com/lists/osflash.org/osflash/0/1908.html">archive</a>. Basically I have to use the 'open' command to launch the app - something like this:<br />
<code><pre><br />
&lt;exec executable="open"&gt;<br />
    &lt;arg line="${pathToFlashPlayer}"/&gt;<br />
    &lt;arg line="${pathToSWFToPlay}"/&gt;<br />
&lt;/exec&gt;</pre><br />
</code><br />
I tried this, and it worked nicely. The problem is that my ant build needs to wait until the test harness runs and closes the player before reading the log and parsing the results. In the ant script above, the open command only stalls the ant script until it has finished doing its opening magic, so ant gets upset as the test results haven't been written yet. I slept on this, then couldn't think of an answer so I sent an email to the <a href="http://www.nabble.com/Running-.app-on-Mac-OSX-tf3908536.html">ant users </a> mailing list. Mere minutes later I got a <a href="http://www.nabble.com/Running-.app-on-Mac-OSX-tf3908536.html">reply</a> that helped me work out how to crack this.<br />
Basically, ant has the ability to run two threads, and move on when they are both complete. So in one thread we launch the player, and in another thread we first wait for the file to be available, then we do a check to see if it contains what we want (I am testing against the flag <code>-----------------TESTRUNNEROUTPUTENDS----------------</code> which I used in my result printer).  It worked like a charm:<br />
<code><pre><br />
&lt;target name="runTest" description="runs the test harness" depends="compileTest"&gt;<br />
	 &lt;parallel&gt;<br />
		 &lt;exec executable="open" spawn="no"&gt;<br />
		 	 &lt;arg line="${debugPlayer}"	/&gt;<br />
		     &lt;arg line="'${testHarness.swf}'"/&gt; <br />
		 &lt;/exec&gt;<br />
		 &lt;sequential&gt;<br />
			 &lt;waitfor&gt;<br />
			 	&lt;available file="${flashlog.location}"/&gt;<br />
			 &lt;/waitfor&gt;<br />
		     &lt;waitfor&gt;<br />
		     	&lt;isfileselected file="${flashlog.location}"&gt;<br />
		     		&lt;contains text="-----------------TESTRUNNEROUTPUTENDS----------------"/&gt;<br />
		     	&lt;/isfileselected&gt;<br />
		     &lt;/waitfor&gt;<br />
		 &lt;/sequential&gt;<br />
	&lt;/parallel&gt;<br />
&lt;/target&gt;<br />
</pre><br />
</code><br />
The last step to making this properly cross platform was to have the right <code>&lt;exec&gt;</code> command called depending on the OS. Fortunatly there is an <code>os</code> attribute you can specify on <code>&lt;exec&gt;</code> and the task will only run if the os matches the platform you are running the task on. A few minutes later, I had my amended runTest target:<br />
<code><pre>&lt;target name="runTest" description="runs the test harness" depends="compileTest"&gt;<br />
	 &lt;parallel&gt;<br />
		 &lt;exec executable="${debugPlayerWin}" spawn="no" os="Windows XP"&gt;<br />
		     &lt;arg line="'${testHarness.swf}'"/&gt; <br />
		 &lt;/exec&gt;<br />
		 &lt;exec executable="open" spawn="no" os="Mac OS X"&gt;<br />
		 	 &lt;arg line="${debugPlayerMac}"	/&gt;<br />
		     &lt;arg line="'${testHarness.swf}'"/&gt; <br />
		 &lt;/exec&gt;<br />
		 &lt;sequential&gt;<br />
			 &lt;waitfor&gt;<br />
			 	&lt;available file="${flashlog.location}"/&gt;<br />
			 &lt;/waitfor&gt;<br />
		     &lt;waitfor&gt;<br />
		     	&lt;isfileselected file="${flashlog.location}"&gt;<br />
		     		&lt;contains text="-----------------TESTRUNNEROUTPUTENDS----------------"/&gt;<br />
		     	&lt;/isfileselected&gt;<br />
		     &lt;/waitfor&gt;<br />
		 &lt;/sequential&gt;<br />
	&lt;/parallel&gt;<br />
&lt;/target&gt;<br />
</pre></code></p>

<p>I'm planning to post my completed project build script and step through it in more detail than I did <a href="http://www.eyefodder.com/blog/2006/05/continuous_integration_with_fl_2.shtml">previously</a>. I've updated it quite a lot in the last year, and so far, I think its a lot neater. Before I do that, I'm going to post about my removing the python dependency from my CI process.</p>]]>
    </content>
</entry>
<entry>
    <title>Restarting cruisecontrol on Mac OSX</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/06/restarting_cruisecontrol_on_ma.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=36" title="Restarting cruisecontrol on Mac OSX" />
    <id>tag:www.eyefodder.com,2007:/blog//1.36</id>
    
    <published>2007-06-11T15:30:48Z</published>
    <updated>2007-06-12T22:53:07Z</updated>
    
    <summary>OK, so for those of you who know Unix better than me (which is probably most of you) this post will be like teaching your granny to suck eggs, but for the rest of us, it took me some working...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Continuous Integration" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>OK, so for those of you who know Unix better than me (which is probably most of you) this post will be like teaching your granny to suck eggs, but for the rest of us, it took me some working out how to stop and start the cruisecontrol server instance on the mac...</p>]]>
        <![CDATA[<p>You see, on windows, I just press ctrl+c and the process terminates so you can then restart the sever. Well, on the mac, that doesn't happen; if you ctrl+c, the server instance still runs. So, thanks to some <a href="http://sourceforge.net/mailarchive/forum.php?thread_name=C28F09C4.5904%25pbh%40adobe.com&forum_name=cruisecontrol-user">friendly assistance</a>, I found out how to kill the server. What you need to do first is type <code>ps -e</code>. This will list all the processes running. The one you are looking for will look something like this:<br />
<code>3267   p2  S  0.15.38   /System/Library/Frameworks/JavaVM.framework/Home/bin/java -Djavax.management.build</code>.<br />
When you have that, note the PID, and then type <code>kill -9 XXXX</code> where XXXX is the pid you found in the previous step.</p>]]>
    </content>
</entry>
<entry>
    <title>CruiseControl on Mac OSX</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/06/cruisecontrol_on_mac_osx.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=35" title="CruiseControl on Mac OSX" />
    <id>tag:www.eyefodder.com,2007:/blog//1.35</id>
    
    <published>2007-06-08T17:25:38Z</published>
    <updated>2007-06-08T17:53:01Z</updated>
    
    <summary>So, I&apos;ve got this shiny new mac provided by my new employers, and so I figured I&apos;d put it to use as a CruiseControl build manager. I found the process reasonably simple but, just like the process of setting up...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Best Practices" />
            <category term="Continuous Integration" />
            <category term="Test Driven Development" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>So, I've got this shiny new mac provided by my new <a href="http://www.adobe.com">employers</a>, and so I figured I'd put it to use as a CruiseControl build manager. I found the process reasonably simple but, just like the process of setting up<a href="http://www.eyefodder.com/blog/2007/06/subversion_and_finder_integrat.shtml"> Subversion and SCPlugin</a>, there are a couple of extra steps I figured I'd share...</p>]]>
        <![CDATA[<p>First step, download the latest source from the downloads page <a href="http://cruisecontrol.sourceforge.net/download.html">here</a>. Simply expand that to where you want your CruiseControl instance to live. Next open up a terminal window, and type the following:<br />
<code>cruisecontrol.sh</code><br />
More than likely, you will get the following error message:<br />
<code>-bash: cruisecontrol.sh: command not found</code><br />
More hunting on the mighty <a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html">intergoogle</a> and a quick look at 'bash guide for beginners' told me the answer - I need to tell bash which shell to use to execute the cruisecontrol.sh script. I found either of the following lines worked:<br />
<code>sh cruisecontrol.sh<br />
bash -x cruisecontrol.sh</code><br />
I'm not a Unix geek, so I don't pretend to know what the difference is, or which is preferable - if anyone can tell me I'd love to know..</p>]]>
    </content>
</entry>
<entry>
    <title>Subversion and Finder integration for the Mac</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2007/06/subversion_and_finder_integrat.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=33" title="Subversion and Finder integration for the Mac" />
    <id>tag:www.eyefodder.com,2007:/blog//1.33</id>
    
    <published>2007-06-08T16:37:37Z</published>
    <updated>2007-06-28T03:39:13Z</updated>
    
    <summary>I just had to sort out getting subversion up and running on a mac. It&apos;s not quite as simple a process as on a PC; there are a couple of extra steps I thought I&apos;d share......</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Best Practices" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>I just had to sort out getting subversion up and running on a mac. It's not quite as simple a process as on a PC; there are a couple of extra steps I thought I'd share...</p>]]>
        <![CDATA[<p>So, the first step is to make sure you're logged in with admin rights, then go and grab the latest copy of subversion from <a href="http://downloads.open.collab.net/binaries.html">here</a></p>

<p>When you have downloaded this, run it and let it do its magic, and you should have subversion installed. To confirm, open a terminal window (Applications/Utilities/Terminal) and type <code>svn</code>. At this stage, its entirely likely you get a 'command not found' error. So after ab bit of digging on the <a href="http://subversion.open.collab.net/servlets/ProjectForumMessageView?forumID=43&messageID=1510">intergoogle</a> I found that someone had the same problem and fixed it by typing the following into the terminal:<br />
<code>sudo ln -s /usr/local/bin/svn /usr/bin/svn</code><br />
This adds a link from the svn binary in your local bin folder to /usr/bin</p>

<p>Type in <code>svn</code> and you should now see the more helpful message <code>Type 'svn help' for usage.</code>. So far so good, you can now use svn on the command line. But if you're anything like me, I want my source control to be seamless and have finder integration. Enter SCPlugin.</p>

<p><a href="http://scplugin.tigris.org/">SCPlugin</a> is an open source plugin based on the idea of <a href="http://tortoisesvn.tigris.org/">TortoiseSVN</a>. Its not quite as mature as TortoiseSVN, but I've found it to be pretty good, barring one gotcha I'll deal with in a minute. For now, <a href="http://scplugin.tigris.org/servlets/ProjectDocumentList">download</a> the latest version, and look at the <a href="http://scplugin.tigris.org/installation.html">installation instructions</a>. Now when I pull up a contextual menu, I should see a subversion submenu. It doesn't have all subversion commands, but it certainly has the ones I use day to day.</p>

<p>I thought I was doing pretty well, until I tried to checkout the latest source from one of my projects. I got a nasty error:<br />
<code><br />
Error: PROPFIND request failed on '/path/to/SVN' <br />
Error: PROPFIND '/path/to/SVN': could not connect to server (https://sample.svnserver.domain) <br />
</code><br />
more hunting on the <a href="http://codebetter.com/blogs/darrell.norton/comments/134379.aspx">intergoogle</a> uncovered a similar problem with Tortoise, so I figured it might be the same thing. Basically my svn repository under https has a self-signed certificate, and SCPlugin just spits the dummy when it comes across this. I went back to my Terminal window and tried to checkout from there:<br />
<code><pre>svn co http://path/to/repos/ </pre><code> </p>

<p>Sure enough, a message came up telling me that the certificate was unsigned (because my friend self-signed it):<br />
<code><pre><br />
Error validating server certificate for 'https://xxxxx':<br />
 - The certificate is not issued by a trusted authority. Use the<br />
   fingerprint to validate the certificate manually!<br />
 - The certificate hostname does not match.<br />
Certificate information:<br />
 - Hostname: eyefodder.com<br />
 - Valid: from Jul 22 15:51:42 2004 GMT until Jul  5 15:51:42 2015 GMT<br />
 - Issuer: Eyefodder, uk<br />
 - Fingerprint: d9:86:9c:31:2a:xx:d2:xx:20:08:f6:78:a6:0f:46:27:a4:52:d1:7b<br />
(R)eject, accept (t)emporarily or accept (p)ermanently? <br />
</pre></code></p>

<p>but in the command line I had the option to accept the certificate permanently (p). I did this, and now when I go back to the SCPlugin contextual, everything works as it should..</p>

<p>Next step - <a href="http://www.eyefodder.com/blog/2007/06/cruisecontrol_on_mac_osx.shtml">cruisecontrol on the Mac...</a></p>]]>
    </content>
</entry>
<entry>
    <title>LinkBar tied to component states</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/08/linkbar_tied_to_component_stat.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=31" title="LinkBar tied to component states" />
    <id>tag:www.eyefodder.com,2006:/blog//1.31</id>
    
    <published>2006-08-16T17:57:27Z</published>
    <updated>2006-08-16T18:02:12Z</updated>
    
    <summary><![CDATA[I just did a quick extension of the LinkBar so you can tie it to the states of a component. I haven't tested it throughly yet, so if you find anything weird in there, let me know... usage: &lt;components:StateLinkBar dataProvider="{states}"/&gt;...]]></summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>I just did a quick extension of the LinkBar so you can tie it to the states of a component. I haven't tested it throughly yet, so if you find anything weird in there, let me know...</p>

<p>usage:<br />
<pre><br />
&lt;components:StateLinkBar dataProvider="{states}"/&gt;<br />
</pre></p>]]>
        <![CDATA[<p>you can <a href="http://www.eyefodder.com/downloads/StateLinkBar.as">download the code here</a>, or just cut and paste from below:<br />
<pre><br />
package view.components<br />
{<br />
	import flash.display.DisplayObject;<br />
	import flash.events.MouseEvent;<br />
	<br />
	import mx.controls.LinkBar;<br />
	import mx.core.UIComponent;<br />
	import mx.events.StateChangeEvent;</p>

<p>	public class StateLinkBar extends LinkBar<br />
	{<br />
		private var measurementHasBeenCalled:Boolean = false;<br />
		private var __pendingStates:Array;<br />
		private var __states:Array;<br />
		<br />
		public function StateLinkBar()<br />
		{<br />
			super();<br />
			labelField = "name";<br />
		}<br />
		override public function set dataProvider(value:Object):void{<br />
			super.dataProvider = value;<br />
			if(value==parentDocument.states){<br />
				setStateListeners(value as Array);<br />
			}<br />
		}<br />
		override protected function commitProperties():void{<br />
			super.commitProperties();<br />
			if(!measurementHasBeenCalled && __pendingStates){<br />
				measurementHasBeenCalled = true<br />
				setStateListeners(__pendingStates);<br />
			}<br />
		}<br />
		override protected function clickHandler(event:MouseEvent):void{<br />
			if(__states){<br />
				var index:int = getChildIndex(DisplayObject(event.currentTarget));<br />
				var uic:UIComponent = parentDocument as UIComponent;<br />
				uic.currentState = __states[index].name;<br />
				hiliteSelectedNavItem(index);<br />
			}<br />
			super.clickHandler(event);<br />
		}<br />
		private function setStateListeners(arr:Array):void{<br />
			if(!measurementHasBeenCalled){<br />
				__pendingStates = arr;<br />
				invalidateProperties();<br />
				return;<br />
			}<br />
			var p:UIComponent = parentDocument as UIComponent;<br />
			if(p !=null){<br />
				__states = arr;<br />
				//setup listeners<br />
				p.addEventListener(StateChangeEvent.CURRENT_STATE_CHANGE,onParentStateChange);<br />
			}<br />
		}<br />
		private function onParentStateChange(event:StateChangeEvent):void{<br />
			var newState:String = event.newState;<br />
			if(__states){<br />
				var max:Number = __states.length;<br />
				for (var i:Number=0;i<max;++i){<br />
					if(__states[i].name==newState){<br />
						selectedIndex = i<br />
						hiliteSelectedNavItem(i);<br />
					}<br />
				}<br />
			}<br />
		}<br />
		<br />
	}<br />
}<br />
</pre></p>]]>
    </content>
</entry>
<entry>
    <title>How I built those firefox plugins to google search a site</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/08/how_i_built_those_firefox_plug.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=30" title="How I built those firefox plugins to google search a site" />
    <id>tag:www.eyefodder.com,2006:/blog//1.30</id>
    
    <published>2006-08-10T21:04:43Z</published>
    <updated>2008-04-28T00:02:58Z</updated>
    
    <summary>Ok, so Mathias just asked how I managed to get the plugins to just search one site. I started to write a comment explaining it, but got a little long, so here&apos;s Paul&apos;s quick n dirty ghetto way of getting...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>Ok, so Mathias just asked how I managed to get the plugins to just search one site. I started to write a comment explaining it, but got a little long, so here's Paul's quick n dirty ghetto way of getting a firefox plugin to search just one site...</p>]]>
        <![CDATA[<p>So basically, I got started by looking at the <a href="http://mycroft.mozdev.org/deepdocs/quickstart.html#firstplugin">mycroft quickstart guide to building your first search plugin</a>.  That helped me to understand the basics of what I wanted to do, but really all I needed was a google search restricted to one site, just like typing site:livedocs.macromedia.com/flex/2 [myterm] into google.</p>
<p>The search plugin format is pretty simple. Basically, you tell it what url to use, and then you can append querystring values on to the end of it using the following syntax:</p>
<pre>&lt;input name="parameterName" value="parameterValue/&gt;</pre>
<p>Then for the user input, you simple use the value 'user' instead of writing value='blah'. So, if you take a look at the google search plugin source (should be found somewhere like 'C:\Program Files\Mozilla Firefox\searchplugins\google.src') you will see a node that looks like this:</p>
<pre>&lt;input name="q" user&gt;</pre>
<p>So, what I actually wanted to do is append 'site:livedocs.macromedia.com/flex/2' to my 'q' querystring value that the user enters. After a bit of digging, I found that you can repeat input nodes of the same 'name' and firefox simply joins these values together. so, in order to search just in the livedocs site, my input nodes looked like this:</p>
<pre>
&lt;input name="q" value="site:livedocs.macromedia.com/flex/2 "/&gt;
&lt;input name="q" user&gt;</pre>
<p>You should be able to find my flex plugin source files in a location similar to this: C:\Documents and Settings\[USERNAME]\Application Data\Mozilla\Firefox\Profiles\ytb1w5n7.default\searchplugins. If you can't be arsed to go digging, you can download them <a href="http://www.eyefodder.com/downloads/flexcoders.src">here</a> and <a href="http://www.eyefodder.com/downloads/flex2LiveDocs.src">here</a></p>]]>
    </content>
</entry>
<entry>
    <title>Finding Flex Facts Faster</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/08/finding_flex_facts_faster.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=29" title="Finding Flex Facts Faster" />
    <id>tag:www.eyefodder.com,2006:/blog//1.29</id>
    
    <published>2006-08-09T21:53:59Z</published>
    <updated>2007-02-13T17:51:34Z</updated>
    
    <summary>so today, firefox decided to die a death on me. I choked it doing some Flex debugging and as a result I lost the functionality in my search bar. This got me thinking about what would really be useful for...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Best Practices" />
            <category term="Flex" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>so today, firefox decided to die a death on me. I choked it doing some Flex debugging and as a result I lost the functionality in my search bar. This got me thinking about what would really be useful for me is a way to search the places I usually go for flex info - the livedocs and the flexcoders mailing list. What I've ended up with is a quick way to search both these resources at the same time...<br />
</p>]]>
        <![CDATA[<p>So, the first thing I did was to create a couple of specialised search bar engines using google. My first thought was to try and get google to search two site: locations in the same query, but it just wont let you... as it turned out, the solution I came up with I think is more usable.</p>
<p>
The first thing you will want to do is install the search plugins. You can get the <a href="javascript:addEngine('flexcoders','png','Flex',0)">flexcoders one here</a>, and the <a href="javascript:addEngine('flex2LiveDocs','png','Flex',0)">livedocs one here.</a> When you have installed them, restart firefox and your search engines should now appear in the searchbar at the top right of your window</p>
<p>The next thing I wanted to do is combine the functionality of these two together. After a few minutes digging, I found that the advanced search sidebar plugin for firefox does exactly what I need it to do. If you dont have it, you can <a href="https://addons.mozilla.org/firefox/1271/" target="_blank">get it here</a>. When you have the search sidebar installed, open it up and in the 'within' dropdown, select 'Edit Categories...' Under the category dropdown, click New... create a category called 'Flex' and add the two flex search engines.</p>
</p>Hey presto, you can now search across livedocs and flexcoders in one action...</p>]]>
    </content>
</entry>
<entry>
    <title>FlexUnit / ASUnit deathmatch results</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/07/flexunit_asunit_deathmatch_res.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=26" title="FlexUnit / ASUnit deathmatch results" />
    <id>tag:www.eyefodder.com,2006:/blog//1.26</id>
    
    <published>2006-07-02T17:08:53Z</published>
    <updated>2007-03-18T15:24:15Z</updated>
    
    <summary>As I mentioned a few posts ago, I am looking into how asunit and flexunit can fit into our continuous integration set up. The move into AS3 has given me an opportunity to reassess how the 2 frameworks fit my/our...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="ASUnit" />
            <category term="Best Practices" />
            <category term="Continuous Integration" />
            <category term="FlexUnit" />
            <category term="Test Driven Development" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>As I mentioned a few <a href="http://www.eyefodder.com/blog/2006/06/unit_test_frameworks_for_as3_a.shtml">posts</a> ago, I am looking into how <a href="http://ww.asunit.org">asunit</a> and <a href="http://labs.adobe.com/wiki/index.php/ActionScript_3:resources:apis:libraries#FlexUnit">flexunit</a> can fit into our continuous integration set up. The move into AS3 has given me an opportunity to reassess how the 2 frameworks fit my/our needs. The prior post set out the criteria I was testing against - here is what I found...</p>]]>
        <![CDATA[<h2>Overall</h2>
<p>Both frameworks seem to have followed the junit framework, and attempted a port from java to AS3. The good thing about  this is that there are very close similarities between usage of the two frameworks, and so switching from one to the other isn't too much of a ballache. Both setups have the notion of a testRunner and resultPrinter, and I actually found that it was a very simple affair to adapt the <a href="http://www.eyefodder.com/blog/2006/06/flexunit_for_cruise_control_xm.shtml">code I wrote to use FlexUnit with Cruise Control</a> to work with ASUnit instead.</p>
<p>I did however find a problem when using the ASUnit testListener. When you run a test, the following methods get called on any testListeners you have (in my case its the CruiseControlResultPrinter):
<ol>
<li>startTest</li>
<li>If an error / failure occurs:<ul><li>addError</li>
<li>addFailure</li>
</ul>
</li>
<li>endTest</li>
</ol>
The problem is that when startTest gets clled, the getCurrentMethod() method of the testCase returns null instead of the testMethod that is about to be executed. If you have had a nosy at my result printer code, you will see that I need this method to return the correct value when startTest gets called so I can append a testCase node with the method name as its 'name' attribute. I managed to work around this by allowing a node to be added with a 'null' value for its name; then when I try and access the testcase node, it first searches for a node with a matching name attribute, then for a node with a value of null for the name. I didn't feel very comfortable with this, as it injects a weak link in my code. However, it wasn't enough for me to strongly favour one framework over the other yet...</p>
<p>The next problem I had with ASUnit was unfortunately for me a show stopper. One of my criteria is that I am able to execute an asynchronous test (as well as asynchronous test setup). Unfortunately I didn't manage to find a clean solution for doing this in ASUnit. There was a <a href="http://sourceforge.net/mailarchive/forum.php?thread_id=14658324&forum_id=42743">discussion on the mailing list </a>about how one might go about doing this, but unfortunately I couldnt find a solution that worked within my requirements. Luke made a very good point about the difference between asynchronous and event-driven, but nevertheless I still couldnt get an async test to work and correctly report back before the alltestscomplete event gets triggered with the test suite.</p>
<p>One of my other criteria was also that the framework didnt rely on Flex. For me right now, this is secondary as my current work is using Flex. However, it is still important to me to be able to have the ability to build a test suite for a flash based project. As far as I can see, the only real reliance Flexunit has on flex is the testRunner / result printer that ships with the framework. This would mean that if I needed to, I could build a flash only test runner. I think that the name flexunit doesn't help, and if it were me, I'd be tempted to find a different name.</p>
<p>I also really like the ability to automatically create test suites that ASUnit provides. <a href="http://www.lennel.org/blog/2006/02/27/building-unit-tests-in-eclipse-from-an-ant-script-for-asunit/">Johannes pulled out the functionality for this to enable us to do this as a python script,</a> so I guess with different templates, you could get this working for flexunit.</p>
<h2>In conclusion</h2>
<p>If you have got this far, I guess you will have worked out that I will be going with flexunit for the time being. I'm kind of sad about this - I suppose I'm quite attached to ASUnit, as Ive been using it for a year and a half, and I really like the community spirit behind it. Ultimately though, it doesnt quite do what I need, and I really didnt want to get deeply under the hood of the framework code. I'm going to keep a very open mind on this decision, and see how asunit progresses. If anyone has anything to add to sway my decision one way or the other, I'd love to hear it too...</p>]]>
    </content>
</entry>
<entry>
    <title>If you think the IT industry is bad at estimating...</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/06/if_you_think_the_it_industry_i.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=25" title="If you think the IT industry is bad at estimating..." />
    <id>tag:www.eyefodder.com,2006:/blog//1.25</id>
    
    <published>2006-06-26T01:29:29Z</published>
    <updated>2007-05-12T15:48:44Z</updated>
    
    <summary>You should try the moving industry. I have just hung up my boots at Fidelity to move deep undercover doing some work in New York (via Washington DC, but thats a whole other story). I&apos;m initially going to be staying...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<h2>You should try the moving industry. </h2>
<p>I have just hung up my boots at Fidelity to move deep undercover doing some work in New York (via Washington DC, but thats a whole other story).  I'm initially going to be staying in a hotel, so I decided  to put my furniture in storage. I'm also moving in kind of a hurry, so I needed to have the movers pack my stuff for me. So I asked them for a quote based on a 1 bedroom apartment, a kitchen's worth of saucepans & crockery, a PC, some furniture and a few bits and bobs.</p>
<p>The quote was for 3 men for 3 hours and about 3-400 dollars of packing costs. This seemed pretty reasonable (I really dont have too much stuff), so I decided to go with these guys. Anyways, I have just been charged for 3 men for 9 hours, and also been charged for 900 dollars of packing costs. I'm still so angry about this I'm not sure if its a scam, or if I didnt give them enough information, but to get an estimate out by a factor of 6 is just plain ridiculous...</p>]]>
        
    </content>
</entry>
<entry>
    <title>FlexUnit UI factory</title>
    <link rel="alternate" type="text/html" href="http://www.eyefodder.com/blog/2006/06/flexunit_ui_factory.shtml" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.eyefodder.com/admin/mt-atom.cgi/weblog/blog_id=1/entry_id=24" title="FlexUnit UI factory" />
    <id>tag:www.eyefodder.com,2006:/blog//1.24</id>
    
    <published>2006-06-16T20:19:51Z</published>
    <updated>2007-02-11T17:01:51Z</updated>
    
    <summary>When I started looking into how we could use flexunit in our CI build, I was struck by how the UI is closely linked to the actual running of the test suite. I really wanted to be able to use...</summary>
    <author>
        <name>Paul BH</name>
        <uri>www.eyefodder.com</uri>
    </author>
            <category term="Best Practices" />
            <category term="Continuous Integration" />
            <category term="Flex" />
            <category term="FlexUnit" />
            <category term="Test Driven Development" />
    
    <content type="html" xml:lang="en" xml:base="http://www.eyefodder.com/blog/">
        <![CDATA[<p>When I started looking into how we could use flexunit in our CI build, I was struck by how the UI is closely linked to the actual running of the test suite. I really wanted to be able to use the supplied flexunit GUI out of the box - after all, it does everything the developer needs, and yet in order to have the results understood by our build process, we would need the results <a href="http://www.eyefodder.com/blog/2006/06/flexunit_for_cruise_control_xm.shtml">printed out differently</a>. </p>
<p>To acheive this, my Flexunit test harness uses a factory method pattern to decide how torunthe test suite. Here's how...</p>]]>
        <![CDATA[<p>I first started by taking the skeleton flexunit testsuite implementation outlined by Darron Schall <a href="http://www.darronschall.com/weblog/archives/000216.cfm">here</a>. Next, I removed the testRunner MXML node, and changed my creationComplete function to look like this:</p>
<pre>
private function onCreationComplete():void{
  var testRunner:IFlexUnitUI = FlexUnitUIFactory.createUI();
  var visualTR:UIComponent = testRunner as UIComponent;
  addChild(visualTR) 
  visualTR.percentWidth = 100;
  visualTR.percentHeight = 100;				
  testRunner.setTest(createSuite());
  testRunner.startTest();
}
</pre>
<p>OK, so far this doesnt really tell you guys much, so lets delve a little deeper into whats going on... my test runner satisfies an interface that simply allows me to set a test and start a test. This decouples the way we run our tests (and display our results) from the main testHarness. The <a href="http://www.eyefodder.com/blog/downloads/IFlexUnitUI.as">flexUnitUIFactory</a>
is a very simple interface:</p>
<pre>package com.fmr.flexunit
{
	import flexunit.framework.TestSuite;
	
	public interface IFlexUnitUI
	{
		function setTest(t:TestSuite):void;
		function startTest():void;
	}
}
</pre>
<p>Now, lets look at the factory itself:</p>
<pre>package com.fmr.flexunit
{
	import flash.system.Capabilities;
	
	//creates an IFlexUnit UI for use by the test harness.
	// the idea is that one can have either visual feedback, or a lightweight text feedback, depending on requirements
	public class FlexUnitUIFactory
	{
		public static function createUI():IFlexUnitUI{
			var environment:String = Capabilities.playerType;
			var outObj:IFlexUnitUI;
			switch(environment){
				case "StandAlone":
					outObj = new TextOutputUI();
					break;
				case "PlugIn":
				default:
					outObj = new FlexUnitUI();
					break;
			}
			return outObj;
		}
	}
}</pre>
<p>The factory is actually very simple - it chooses a TextOutputUI if its running in a standalone player (and thus being run as an ANT build), or uses a pretty GUI if in the browser (thus being run by the developer). Each of these UI's must satisfy our interface, and so I needed to subclass the flexunit GUI to get it to satisfy the interface:
<pre>
>package com.fmr.flexunit
{
	import flexunit.flexui.TestRunnerBase;
	import flash.events.Event;
	import flexunit.framework.TestSuite;
	
	public class FlexUnitUI extends TestRunnerBase implements IFlexUnitUI
	{
		public static var testsCompleteEvent:String = "testsComplete";
		override public function onAllTestsEnd() : void {
			super.onAllTestsEnd();
			dispatchEvent(new Event(testsCompleteEvent));
		}
		
		public function setTest(t:TestSuite):void{
			test = t;
		}
	}
}
</pre>
<p>The TextOutputUI uses our CruiseControl friendly outputting classes, and is simply a VBox (as we need our elememnt to be a IUObject that can be atached to our main app):</p>
<pre>
&lt;mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" implements="com.fmr.flexunit.IFlexUnitUI"&gt;
	&lt;mx:Script&gt;
		&lt;![CDATA[
			import flexunit.framework.TestSuite;
			import flexunit.textui.TestRunner;
		
			public var test:TestSuite;
			
			public function setTest(t:TestSuite):void{
				test = t
			}
			public function startTest():void{
				CruiseControlTestRunner.run( test, onTestsComplete );
			}
			private function onTestsComplete():void{
				fscommand("quit");
			}
		]]&gt;
	&lt;/mx:Script&gt;
&lt;/mx:VBox&gt;
</pre> 
<p>Notice also that in our textOutputUI, when the tests are complete, the app is told to quit - this is a requirement of our ANT build process as once the unit tests are run, the main app should be built. </p>
<p>And that's basically it. Using this method, our test harness can run differently depending on its environment. I havent had a chance to test this in the field yet, but I'll let you know how it all works out...</p>]]>
    </content>
</entry>

</feed> 

