Code Coverage with Flex - a headless agent for CI builds

July 28, 2009

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.

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...

The approach

So here's the basic plan:
  1. Swap out the default localConnection reporting mechanism for one that will pick and choose depending on environment the app is running in
  2. Create a headless agent that will pull the coverage data collection and reporting side of the coverageViewer into the app
  3. Use commandline options to swap between the headless agent and local connection agent
  4. Default to using the localConnnection agent

How it works

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:
private function injectAgent():void{
	CoverageManager.agent = new CoverageAgentSwitch();
}

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:


-coverage-agent-type=headless Headless is only option, anything else will default to localConnectionAgent
-coverage-metadata='/full/path/to/coverage/metadata.cvm'
-coverage-output='/full/path/to/coverage/reportInOriginalFormat.cvr'
-emma-report='/full/path/to/coverage/reportInEmmaFormat.xml'

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.

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.

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.

The Result

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.

coverageCIBad.gif
Coverage trend without crazy variance found using the external viewer

Download headless agent library

Code Coverage with Flex - ANT build for running the viewer

July 25, 2009

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's not very consistent in its reporting and I'll explain why at the end...

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:

  1. clean my output folders (delete and recreate them)
  2. Compile the main application using the instrumented SDK. This will generate the .cvr metadatafile that the coverageViewer needs
  3. Compile the test harness using the instrumented SDK. This is so that when it runs, the hooks injected by the SDK report coverage data.
  4. Launch the Coverage Viewer Application (specifying EMMA output file)
  5. Run the test harness. When it is finished, call CoverageManager.exit() which will close the coverage viewer
  6. Wait for the test results and coverage report to be available. By implication this means that the test harness and coverage viewer have quit.
  7. Compile the main app using the standard SDK
  8. (AIR Apps only) remove test harness and any test data from the output folder
  9. (AIR Apps only) package up the application

In theory this is all well and good. In practice there are a few problems:

* 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.

* There are two applications being launched by the build process. In order for this to work, you need to launch the coverageViewer with spawn='true' 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..)

* 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.

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:

coverageCIBad.gif
Coverage trend showing wide variance of reporting results


I was left with one of two conclusions:


  1. There was a bug/ fragility in the localConnection and it couldn't be relied on

  2. There was a bug in the coverageAgent.exit() code sequence



The way CoverageAgent.exit() works is that you call it from within your application and it:

  1. Waits until the application has sent all remianing coverage data

  2. Sends a message to the coverage viewer asking it to prepare for exit

  3. The coverage viewer writes out any report files

  4. Exits, and sends a message back to the main application telling it to exit


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...

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 :)

Download build file archive

Code Coverage with Flex - creating EMMA formatted reports

July 24, 2009

Over the last few months I have adopted Hudson 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.

A slightly less crude metric is code coverage, which measures the amount of an application that gets exercised when it's run. FlexCover is a very cool tool for this and props to my colleague - Alex Uhlmann and Joe Berkowitz 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.

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 EMMA formatted reports...

So as I was starting to look at this, I could see one of three paths:


  1. Create a Hudson plugin to consume flexCover's report format

  2. Add some sort of XSLT transform to my build process

  3. Modify FlexCover to be able to output a report format that Hudson understands

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 hack extend flexcover to be able to output EMMA formatted reports.

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 :)

Installation

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...

Usage

In order to write out the coverage report file with the coverage viewer, you need to supply the commandline argument: -output /full/path/to/my/flexcoverreport.xml This functionality is unchanged, but now you can also specify an EMMA formatted file using the following:

-emma-report /full/path/to/my/EmmaReportName.xml

And that's about it! My next post covers the challenges I had integrating this into my build process, and how I overcame them...

Download patch file

« August 2007 | Main

Syndicate

Add to Technorati Favorites Powered by
Movable Type 3.2

Holiday Fund