<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>a little madness &#187; Java</title>
	<atom:link href="http://www.alittlemadness.com/category/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.alittlemadness.com</link>
	<description>A man needs a little madness, or else he never dares cut the rope and be free. -Nikos Kazantzakis</description>
	<lastBuildDate>Wed, 26 Oct 2011 04:14:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Android JUnit XML Reports: Multiple File Support</title>
		<link>http://www.alittlemadness.com/2011/02/23/android-junit-xml-reports-multiple-file-support/</link>
		<comments>http://www.alittlemadness.com/2011/02/23/android-junit-xml-reports-multiple-file-support/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 05:08:55 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=749</guid>
		<description><![CDATA[Due to popular demand, I&#8217;ve added support for multiple output files (one per test suite) to android-junit-report.
For simplicity and efficiency, android-junit-report does not produce files in the exact format used by the Ant JUnit task.  In the 1.1 release there are two main differences:

A single report file is produced containing all test suites.
Redundant information, [...]]]></description>
			<content:encoded><![CDATA[<p>Due to popular demand, I&#8217;ve added support for multiple output files (one per test suite) to <a href="https://github.com/jsankey/android-junit-report">android-junit-report</a>.</p>
<p>For simplicity and efficiency, android-junit-report does not produce files in the exact format used by the Ant JUnit task.  In the 1.1 release there are two main differences:</p>
<ol>
<li>A single report file is produced containing all test suites.</li>
<li>Redundant information, such as the number of cases, failures etc is not added using attributes on the testsuite tag.</li>
</ol>
<p>It turns out the first of these restrictions caused multiple users issues with tools accustomed to handling a single report file per suite.  So in the latest 1.2 release I have added a new multiFile option.  When this option is enabled, android-junit-report produces a separate output file for each test suite.  This does mean that to retrieve the results from the device you will need to pull a whole directory.</p>
<p>To enable this option from an Ant build, you can override the default run-tests target as follows:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;target</span> <span class="re0">name</span>=<span class="st0">&quot;run-tests&quot;</span> <span class="re0">depends</span>=<span class="st0">&quot;-install-tested-project, install&quot;</span></span><br />
<span class="sc3"> &nbsp; &nbsp; &nbsp; &nbsp;<span class="re0">description</span>=<span class="st0">&quot;Runs tests from the package defined in test.package property&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;reports.dir&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;${out.dir}/reports&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;property</span> <span class="re0">name</span>=<span class="st0">&quot;files.dir&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;/data/data/${tested.manifest.package}/files&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;echo<span class="re2">&gt;</span></span></span>Cleaning up previous test reports&#8230;<span class="sc3"><span class="re1">&lt;/echo<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;delete</span> <span class="re0">dir</span>=<span class="st0">&quot;${reports.dir}&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;exec</span> <span class="re0">executable</span>=<span class="st0">&quot;${adb}&quot;</span> <span class="re0">failonerror</span>=<span class="st0">&quot;true&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">line</span>=<span class="st0">&quot;${adb.device.arg}&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;shell&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;rm&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;${files.dir}/*&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/exec<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;echo<span class="re2">&gt;</span></span></span>Running tests&#8230;<span class="sc3"><span class="re1">&lt;/echo<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;exec</span> <span class="re0">executable</span>=<span class="st0">&quot;${adb}&quot;</span> <span class="re0">failonerror</span>=<span class="st0">&quot;true&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">line</span>=<span class="st0">&quot;${adb.device.arg}&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;shell&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;am&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;instrument&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;-w&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;-e&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;coverage&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;@{emma.enabled}&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;-e&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;multiFile&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;${manifest.package}/${test.runner}&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/exec<span class="re2">&gt;</span></span></span> &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;echo<span class="re2">&gt;</span></span></span>Downloading XML test reports&#8230;<span class="sc3"><span class="re1">&lt;/echo<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;mkdir</span> <span class="re0">dir</span>=<span class="st0">&quot;${reports.dir}&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;exec</span> <span class="re0">executable</span>=<span class="st0">&quot;${adb}&quot;</span> <span class="re0">failonerror</span>=<span class="st0">&quot;true&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">line</span>=<span class="st0">&quot;${adb.device.arg}&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;pull&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;${files.dir}&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;arg</span> <span class="re0">value</span>=<span class="st0">&quot;${reports.dir}&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/exec<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/target<span class="re2">&gt;</span></span></span></div>
</div>
<p>You can learn more about android-junit-report and/or download the new release using the links below:</p>
<ul>
<li><a href="http://www.alittlemadness.com/2010/07/14/android-testing-xml-reports-for-continuous-integration/">Original blog post</a></li>
<li><a href="https://github.com/jsankey/android-junit-report/downloads">Pre-built jar downloads</a></li>
<li><a href="https://github.com/jsankey/android-junit-report">Project home and documentation</a></li>
<li><a href="http://pulse.zutubi.com/browse/projects/android-junit-report-release/">Build Server</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2011/02/23/android-junit-xml-reports-multiple-file-support/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Simpler Ant Builds With the Ant Script Library</title>
		<link>http://www.alittlemadness.com/2010/07/29/simpler-ant-builds-with-the-ant-script-library/</link>
		<comments>http://www.alittlemadness.com/2010/07/29/simpler-ant-builds-with-the-ant-script-library/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 09:39:21 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Build]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Project Automation]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=694</guid>
		<description><![CDATA[Introduction
Ant may be unfashionable these days, but it still has its advantages.  Key among these are familiarity and simplicity: most Java developers have worked with Ant, and with an Ant build what you get is what you see.  A major disadvantage, though, is that Ant provides very little out-of-the-box.  When you start [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p><a href="http://ant.apache.org/">Ant</a> may be unfashionable these days, but it still has its advantages.  Key among these are familiarity and simplicity: most Java developers have worked with Ant, and with an Ant build what you get is what you see.  A major disadvantage, though, is that Ant provides very little out-of-the-box.  When you start a new project, you&#8217;ve got a lot of grunt work to endure just to get your code compiled, packaged, and tested.  An all-too-common solution, in the grand tradition of <a href="http://www.gnu.org/software/make/">make</a>, is to copy a build file from an existing project as an easy starting point.</p>
<p>Over the years, though, Ant has gradually expanded support for creating reusable build file snippets.  On top of this a few projects have emerged which aim to simplify and standardise your Ant builds, including:</p>
<ul>
<li><a href="http://www.easyant.org/">EasyAnt</a></li>
<li><a href="http://code.google.com/p/ant-master-build-scripts/">Ant Master Build Scripts</a></li>
<li><a href="http://www.exubero.com/asl/">Ant Script Library</a></li>
</ul>
<p>Today I&#8217;ve taken my first proper look at the latter, and so far I like what I see.</p>
<h3>The Ant Script Library</h3>
<p>In the author Joe Schmetzer&#8217;s own words:</p>
<blockquote><p>The Ant Script Library (ASL) is a collection of re-usable Ant scripts that can be imported into your own projects. The ASL provides a number of pre-defined targets that simplify setting up build scripts for a new project, bringing re-use and consistency to your own Ant scripts.</p></blockquote>
<p>ASL consists of several Ant XML files, each of which provides a group of related functionality via predefined targets.  For example, the <b>asl-java-build.xml</b> file defines targets for compiling and packaging Java code.  The <b>asl-java-test.xml</b> file extends this with the ability to run JUnit tests, and so on.  Essentially, ASL packages up all the grunt work, allowing you to concentrate on the small tweaks and extra targets unique to your project.  The modular structure of ASL, combined with the fact that it is just Ant properties and targets, makes it easy to take what you like and leave the rest.</p>
<h3>An Example</h3>
<p>Allow me to illustrate with a simple project I have been playing with.  This project has a straightforward directory structure:</p>
<ul>
<li>&lt;project root&gt;
<ul style="font-size: 1em;">
<li>asl/ &#8211; the Ant Script Library</li>
<li>build.xml &#8211; Ant build file</li>
<li>lib/ &#8211; Jar file depedencies</li>
<li>src/ &#8211; Java source files</li>
<li>test/ &#8211; JUnit-based test source files</li>
</ul>
</li>
</ul>
<p>To add ASL to my project, I simply downloaded it from the project <a href="http://www.exubero.com/asl/download.html">download page</a> and unpacked it in the <b>asl/</b> subdirectory of my project<sup>1</sup>.  Then I can start with a very simple build file that supports building my code and running the tests:</p>
<pre class="brush: xml;">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;project name=&quot;zutubi-android-ant&quot; default=&quot;dist&quot;&gt;
    &lt;property name=&quot;java-build.src-dir&quot; location=&quot;src&quot;/&gt;
    &lt;property name=&quot;java-test.src-dir&quot; location=&quot;test&quot;/&gt;
    &lt;property name=&quot;java-build.lib-dir&quot; location=&quot;libs&quot;/&gt;

    &lt;property name=&quot;asl.dir&quot; value=&quot;asl&quot;/&gt;

    &lt;import file=&quot;${asl.dir}/asl-java-build.xml&quot;/&gt;
    &lt;import file=&quot;${asl.dir}/asl-java-test.xml&quot;/&gt;
&lt;/project&gt;</pre>
<p>Notice that I am using non-standard source locations, but that is easily tweaked using properties which are <a href="http://www.exubero.com/asl/reference.html">fully documented</a>.  With this tiny build file, let&#8217;s see what targets ASL provides for me:</p>
<pre class="brush: plain;">$ ant -p
Buildfile: build.xml

Main targets:

 clean                 Deletes files generated by the build
 compile               Compiles the java source
 copy-resources        Copies resources in preparation to be packaged in jar
 dist                  Create a distributable for this java project
 generate              Generates source code
 jar                   Create a jar for this java project
 test-all              Runs all tests
 test-integration      Runs integration tests
 test-run-integration  Runs the integration tests
 test-run-unit         Runs the unit tests
 test-unit             Runs unit tests
Default target: dist</pre>
<p>It&#8217;s delightfully simple!</p>
<h3>Adding Reports</h3>
<p>It gets better: ASL also provides reporting with tools like <a href="http://cobertura.sourceforge.net/">Cobertura</a> for coverage, <a href="http://findbugs.sourceforge.net/">FindBugs</a> for static analysis and so on via its <b>asl-java-report.xml</b> module.  The full range of supported reports can be seen in the <b>report-all</b> target:</p>
<pre class="brush: xml;">&lt;target name=&quot;report-all&quot;
        depends=&quot;report-javadoc, report-tests, report-cobertura, report-jdepend, report-pmd, report-cpd, report-checkstyle, report-findbugs&quot;
        description=&quot;Runs all reports&quot;/&gt;</pre>
<p>Having support for several tools out-of-the-box is great.  For my project, however, I&#8217;d like to keep my dependencies down and I don&#8217;t feel that I need all of the reporting.  Although the choice of reports is not something that is parameterised by a property, it is still trivial to override by providing your own report-all target.  This shows the advantage of everything being plain Ant targets:</p>
<pre class="brush: xml;">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;project name=&quot;zutubi-android-ant&quot; default=&quot;dist&quot;&gt;
    &lt;property name=&quot;java-build.src-dir&quot; location=&quot;src&quot;/&gt;
    &lt;property name=&quot;java-test.src-dir&quot; location=&quot;test&quot;/&gt;
    &lt;property name=&quot;java-build.lib-dir&quot; location=&quot;libs&quot;/&gt;

    &lt;property name=&quot;asl.dir&quot; value=&quot;asl&quot;/&gt;

    &lt;import file=&quot;${asl.dir}/asl-java-build.xml&quot;/&gt;
    &lt;import file=&quot;${asl.dir}/asl-java-test.xml&quot;/&gt;
    &lt;import file=&quot;${asl.dir}/asl-java-report.xml&quot;/&gt;

    &lt;target name=&quot;report-all&quot;
            depends=&quot;report-javadoc, report-tests, report-cobertura, report-pmd, report-checkstyle&quot;
            description=&quot;Runs all reports&quot;/&gt;
&lt;/project&gt;</pre>
<p>Here I&#8217;ve included the <b>java-report</b> module, but defined my own <b>report-all</b> target that depends on just the reports I want.  This keeps things simple, and allows me to trim out a bunch of ASL dependencies I don&#8217;t need.</p>
<h3>Conclusion</h3>
<p>I&#8217;ve known of ASL and such projects for a while, but this is the first time I&#8217;ve actually given one a go.  Getting started was pleasantly simple, as was applying the small tweaks I needed.  So next time you&#8217;re tempted to copy an Ant build file, give ASL a shot: you won&#8217;t regret it!</p>
<p><br/></p>
<p>&#8211;<br />
<sup>1</sup> In this case I downloaded the full tarball including dependencies, which seemed on the large side (21MB!) but in fact can be easily trimmed by removing the pieces you don&#8217;t need.  Alternatively, you can start with the basic ASL install (sans dependencies) and it can pull down libraries for you.  Sweet <img src='http://www.alittlemadness.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2010/07/29/simpler-ant-builds-with-the-ant-script-library/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Android Testing: XML Reports for Continuous Integration</title>
		<link>http://www.alittlemadness.com/2010/07/14/android-testing-xml-reports-for-continuous-integration/</link>
		<comments>http://www.alittlemadness.com/2010/07/14/android-testing-xml-reports-for-continuous-integration/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 07:57:28 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Build]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=680</guid>
		<description><![CDATA[Summary
This post introduces the Android JUnit Report Test Runner, a custom instrumentation test runner for Android that produces XML test reports.  Using this runner you can integrate your Android test results with tools that understand the Ant JUnit task XML format, e.g. the Pulse Continuous Integration Server.
The motivation and details of the runner are [...]]]></description>
			<content:encoded><![CDATA[<h3>Summary</h3>
<p>This post introduces the <a href="http://github.com/jsankey/android-junit-report">Android JUnit Report Test Runner</a>, a custom instrumentation test runner for Android that produces XML test reports.  Using this runner you can integrate your Android test results with tools that understand the Ant JUnit task XML format, e.g. the <a href="http://zutubi.com/products/pulse/">Pulse</a> Continuous Integration Server.</p>
<p>The motivation and details of the runner are discussed below.  For the impatient: simply head on over to the project <a href="http://github.com/jsankey/android-junit-report">home page</a> on GitHub and check out the README.</p>
<h3>Introduction</h3>
<p>If you&#8217;ve been following my <a href="/2010/06/29/android-functional-testing-vs-dependency-injection/">recent</a> <a href="/2010/07/06/android-testing-using-pure-unit-tests/">posts</a> you&#8217;ll know that I&#8217;ve been figuring out the practical aspects of testing Android applications.  And if you&#8217;ve been following for longer, you might know that my day job is development of the <a href="http://zutubi.com/products/pulse/">Pulse</a> Continuous Integration Server.  So it should come as no surprise that in my latest foray into the world of Android testing I sought to bring the two together <img src='http://www.alittlemadness.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<h3>Status Quo</h3>
<p>Out of the box, the Android SDK supports running functional tests on a device or emulator via <a href="http://developer.android.com/guide/topics/testing/testing_android.html">instrumentation</a>.  Running within Eclipse, you get nice integrated feedback.  Unfortunately, though, there are no real options for integrating with other tools such as continuous integration servers.  Test output from the standard Ant builds is designed for human consumption, and lacks the level of detail I&#8217;d like to see in my build reports.</p>
<h3>The Solution</h3>
<p>On the upside, having access to the Android source makes it possible to examine how the current instrumentation works, and therefore how it can be customised.  I found that the default <a href="http://developer.android.com/reference/android/test/InstrumentationTestRunner.html">InstrumentationTestRunner</a> may be fairly easily extended to hook in extra test listeners.  So I&#8217;ve implemented a custom JUnitReportTestRunner that does just that, with a listener that generates a test report in XML format.  The format is designed to be largely compatible with the output of the Ant <a href="http://ant.apache.org/manual/Tasks/junit.html">JUnit task&#8217;s</a> XML formatter &#8212; the most widely supported format in the Java world.  Tools like Pulse can read in this format to give rich test reporting.</p>
<h3>How It Works</h3>
<p>As mentioned, the JUnitReportTestRunner extends the default InstrumentationTestRunner, so it can act as a drop-in replacement.  The custom runner acts identically to the default, with the added side-effect of producing an XML report.</p>
<p>For consistency with the SDK&#8217;s support for generating coverage reports, the XML report is generated in the file storage area of the <em>target application</em>.  The default report location is something like:</p>
<pre class="brush: plain;">/data/data/&lt;tested application package&gt;/files/junit-report.xml</pre>
<p>on the device.  To retrieve the report, you can use <b>adb pull</b>, typically as part of your scripted build.</p>
<h3>Using the Runner</h3>
<p>Full details on using the runner are provided in the README on the project <a href="http://github.com/jsankey/android-junit-report">home page</a>.  Briefly:</p>
<ul>
<li>Add the android-junit-report-&lt;version&gt;.jar to the libraries for your test application.</li>
<li>Replace all occurrences of <b>android.test.InstrumentationTestRunner</b> with <b>com.zutubi.android.junitreport.JUnitReportTestRunner</b>:
<ul style="font-size: 1em;">
<li>In the <b>android:name</b> attribute of the <b>instrumentation</b> tag in you test application&#8217;s <b>AndroidManifest.xml</b>.</li>
<li>In the <b>test.runner</b> property in the Ant build for your test application (<em>before</em> calling the Android <b>setup</b> task).</li>
<li>In the <b>Instrumentation runner</b> field of all Android JUnit Run Configurations in your Eclipse project.</li>
</ul>
</li>
<li>Add logic to your Ant build to run <b>adb pull</b> to retrieve the report after the tests are run.</li>
</ul>
<p>As an example for retrieving the report in your Ant build:</p>
<pre class="brush: xml;">&lt;target name=&quot;fetch-test-report&quot;&gt;
    &lt;echo&gt;Downloading XML test report...&lt;/echo&gt;
    &lt;mkdir dir=&quot;${reports.dir}&quot;/&gt;
    &lt;exec executable=&quot;${adb}&quot; failonerror=&quot;true&quot;&gt;
        &lt;arg line=&quot;${adb.device.arg}&quot;/&gt;
        &lt;arg value=&quot;pull&quot; /&gt;
        &lt;arg value=&quot;/data/data/${tested.manifest.package}/files/junit-report.xml&quot; /&gt;
        &lt;arg value=&quot;${reports.dir}/junit-report.xml&quot; /&gt;
    &lt;/exec&gt;
&lt;/target&gt;</pre>
<h3>In the Wild</h3>
<p>You can see a complete example of this in action in my simple <a href="http://github.com/jsankey/droidscope">DroidScope</a> Android application.  The custom runner is applied in the droidscope-test application in the test/ subdirectory.  You can even see the <a href="http://pulse.zutubi.com/browse/projects/droidscope/builds/latest/tests/default/">test results</a> being picked up by Pulse on our demo server.  Note that some of the tests are <a href="/2010/07/06/android-testing-using-pure-unit-tests/">pure unit tests</a>, which are run on a regular JVM, whereas others are run with the custom runner on an emulator.  It&#8217;s nice for all the results to be collected together!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2010/07/14/android-testing-xml-reports-for-continuous-integration/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Android Functional Testing vs Dependency Injection</title>
		<link>http://www.alittlemadness.com/2010/06/29/android-functional-testing-vs-dependency-injection/</link>
		<comments>http://www.alittlemadness.com/2010/06/29/android-functional-testing-vs-dependency-injection/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 08:04:28 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=654</guid>
		<description><![CDATA[I commonly use Dependency Injection (DI) to create testable Java code.  Dependency injection is simple: instead of having your objects find their own dependencies, you pass them in via the constructor or a setter.  One key advantage of this is the ability to easily substitute in stub or mock dependencies during testing.
Naturally, as [...]]]></description>
			<content:encoded><![CDATA[<p>I commonly use <a href="http://jamesshore.com/Blog/Dependency-Injection-Demystified.html">Dependency Injection</a> (DI) to create testable Java code.  Dependency injection is simple: instead of having your objects find their own dependencies, you pass them in via the constructor or a setter.  One key advantage of this is the ability to easily substitute in stub or mock dependencies during testing.</p>
<p>Naturally, as I started working on an Android application, I tried to apply the same technique.  Problems arose when I tried to combine DI with the Android SDK&#8217;s <a href="http://developer.android.com/guide/topics/testing/testing_android.html">Testing and Instrumentation</a> support.  In particular, I am yet to find a suitable way to combine DI with functional testing of Android activities via <a href="http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html">ActivityInstrumentationTestCase2</a>.  When testing an activity using the instrumentation support, injection of dependencies is foiled by a couple of factors:</p>
<ol>
<li>Constructor injection is impossible, as activities are constructed by the framework.  I experimented with various ways of creating the Activity myself, but was unable to maintain a connection with the Android system for true functional testing.</li>
<li>Setter injection is fragile, as activities are started by the framework as soon as they are created.  There is no time to set stub dependencies between the instantiation of the Activity and its activation.</li>
</ol>
<p>Not ready to give DI away, I scoured the web for existing solutions to this problem.  Although I did find some DI libraries with Android support (notably <a href="http://code.google.com/p/google-guice/wiki/OptionalAOP">Guice no AOP</a> and <a href="http://code.google.com/p/roboguice/">roboguice</a> which builds upon it), the only testing support I found was restricted to unit tests.  Although roboguice has support for Activities, it relies on being able to obtain a Guice Injector from somewhere &#8212; which just shifts the problem by one level of indirection.</p>
<p>Given how complex any DI solution was going to become (if indeed it is possible at all) I decided to step back and consider alternatives.  A classic alternative to DI is the Service Locator pattern: where objects ask a central registry for their dependencies.  Martin Fowler&#8217;s article <a href="http://martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> compares and contrasts the two patterns in some detail.  Most importantly: a Service Locator still allows you to substitute in different implementations of dependencies at test time.  The main downside is each class is dependent on the central registry &#8212; which can make them harder to reuse.  As I&#8217;m working with Activities that are unlikely to ever be reused outside of their current application, this is no big deal.</p>
<p>Implementation-wise, I went with the simplest registry that works for me.  I found it convenient to use my project&#8217;s <a href="http://developer.android.com/reference/android/app/Application.html">Application</a> implementation as the registry.  In production, the Application onCreate callback is used to create all of the standard dependency implementations.  These dependencies are accessed via simple static getters.  Static setters are exposed to allow tests to drop in whatever alternative dependencies they desire.  A contrived example:</p>
<pre class="brush: java;">public class MyApplication extends Application
{
    private static IService service;
    private static ISettings settings;

    @Override
    public void onCreate()
    {
        super.onCreate();
        if (service == null)
        {
            service = new ServiceImpl();
        }

        if (settings == null)
        {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            settings = new PreferencesSettings(preferences);
        }
    }

    public static IService getService()
    {
        return service;
    }

    public static void setService(IService s)
    {
        service = s;
    }

    public static ISettings getSettings()
    {
        return settings;
    }

    public static void setSettings(ISettings s)
    {
        settings = s;
    }
}</pre>
<p>I access the dependencies via the registry in my Activity&#8217;s onCreate callback:</p>
<pre class="brush: java;">
public class MyActivity extends Activity
{
    private IService service;
    private ISettings settings;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        service = MyApplication.getService();
        settings = MyApplication.getSettings();

        setContentView(R.layout.main);
        // ...
    }

    // ...
}
</pre>
<p>And I wire in my fake implementations in my functional test setUp:</p>
<pre class="brush: java;">
public class MyActivityTest extends ActivityInstrumentationTestCase2&lt;MyActivity&gt;
{
    private MyActivity activity;

    public MyActivityTest()
    {
        super(&quot;com.zutubi.android.example&quot;, MyActivity.class);
    }

    @Override
    protected void setUp() throws Exception
    {
        super.setUp();
        MyApplication.setService(new FakeService());
        MyApplication.setSettings(new FakeSettings());
        activity = getActivity();
    }

    public void testSomething() throws Throwable
    {
        // ...
    }
</pre>
<p>After all of the angst over DI, this solution is delightful in its simplicity.  It also illustrates that static is not always a dirty word when it comes to testing!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2010/06/29/android-functional-testing-vs-dependency-injection/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Are Temp Files Slowing Your Builds Down?</title>
		<link>http://www.alittlemadness.com/2009/11/24/are-temp-files-slowing-your-builds-down/</link>
		<comments>http://www.alittlemadness.com/2009/11/24/are-temp-files-slowing-your-builds-down/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 23:01:33 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Project Automation]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=409</guid>
		<description><![CDATA[Lately one of our Pulse agents has been bogged down, to the extent that some of our heavier acceptance tests started to genuinely time out.  Tests failing due to environmental factors can lead to homicidal mania, so I&#8217;ve been trying to diagnose what is going on before someone gets hurt!
The box in question runs [...]]]></description>
			<content:encoded><![CDATA[<p>Lately one of our <a href="http://zutubi.com/products/pulse/">Pulse</a> agents has been bogged down, to the extent that some of our heavier acceptance tests started to genuinely time out.  Tests failing due to environmental factors can lead to homicidal mania, so I&#8217;ve been trying to diagnose what is going on before someone gets hurt!</p>
<p>The box in question runs Windows Vista, and I noticed while poking around that some disk operations were very slow.  In fact, deleting even a handful of files via Explorer took so long that I gave up (we&#8217;re talking hours here).  About this time I fired up the Reliability and Performance Manager that comes with Vista (Control Panel > Administrative Tools).  I noticed that there was constant disk activity, and a lot of it centered around C:\$MFT &#8212; the NTFS <a href="http://msdn.microsoft.com/en-us/library/bb470206%28VS.85%29.aspx">Master File Table</a>.</p>
<p>I had already pared back the background tasks on this machine: the Recycle Bin was disabled, Search Indexing was turned off and Defrag ran on a regular schedule.  So why was my file system so dog slow?  The answer came when I looked into the AppData\Local\Temp directory for the user running the Pulse agent.  The directory was filled with tens of thousands of entries, many of which were directories that themselves contained many files.</p>
<p>The junk that had built up in this directory was quite astounding.  Although some of it can be explained by tests that don&#8217;t clean up after themselves, I believe a lot of the junk came from tests that had to be killed forcefully without time to clean up.  It was also evident that every second component we were using was part of the problem &#8211; Selenium, JFreechart, JNA, Ant and Ivy all joined the party.</p>
<p>So, how to resolve this?  Of course any tests that don&#8217;t clean up after themselves should be fixed.  But in reality this won&#8217;t always work &#8212; especially given the fact that Windows will not allow open files to be deleted.  So the practical solution is to regularly clean out the temporary directory.  In fact, it&#8217;s quite easy to set up a little Pulse project that will do just that, and let Pulse do the work of scheduling it via a cron trigger.  With Pulse in control of the scheduling there is no risk the cleanup will overlap with another build.</p>
<p>A more general solution is to start with a guaranteed-clean environment in the first place.  After all, acceptance tests have a habit of messing with a machine in other ways too.  Re-imaging the machine after each build, or using a virtual machine that can be restored to a clean state, is a more reliable way to avoid the junk.  Pulse is actually designed to allow reimaging/rebooting of agents to be done in a <a href="http://confluence.zutubi.com/display/pulse0200/Project+Build+Hooks#ProjectBuildHooks-PostStage">post-stage hook</a> &#8212; the agent management code on the master allows for agents to go offline at this point, and not try to reuse them until their status can be confirmed by a later ping.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2009/11/24/are-temp-files-slowing-your-builds-down/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Functional vs &#8220;Java&#8221; Style</title>
		<link>http://www.alittlemadness.com/2009/08/21/functional-vs-java-style/</link>
		<comments>http://www.alittlemadness.com/2009/08/21/functional-vs-java-style/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 13:24:28 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=316</guid>
		<description><![CDATA[Stephan Schmidt started it with his third point:
Do not use loops for list operations. Learning from functional languages, looping isn’t the best way to work on collections. Suppose we want to filter a list of persons to those who can drink beer. The loop versions looks like:

List&#60;Person&#62; beerDrinkers = new ArrayList&#60;Person&#62;&#40;&#41;;
for &#40;Person p: persons&#41; &#123;
&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Stephan Schmidt <a href="http://codemonkeyism.com/generation-java-programming-style/">started it</a> with his third point:</p>
<blockquote><p><strong>Do not use loops for list operations</strong>. Learning from functional languages, looping isn’t the best way to work on collections. Suppose we want to filter a list of persons to those who can drink beer. The loop versions looks like:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">List<span class="sy0">&lt;</span>Person<span class="sy0">&gt;</span> beerDrinkers <span class="sy0">=</span> <span class="kw1">new</span> ArrayList<span class="sy0">&lt;</span>Person<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw1">for</span> <span class="br0">&#40;</span>Person p<span class="sy0">:</span> persons<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>p.<span class="me1">getAge</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&gt;</span> 16<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; beerDrinkers.<span class="me1">add</span><span class="br0">&#40;</span>p<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>This can &#8211; even in Java &#8211; be rewritten to a more a functional programming style. For example using Google collections filter:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">Predicate<span class="sy0">&lt;</span>HasAge<span class="sy0">&gt;</span> canDrinkBeer <span class="sy0">=</span> <span class="kw1">new</span> Predicate<span class="sy0">&lt;</span>HasAge<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">boolean</span> apply<span class="br0">&#40;</span>HasAge hasAge<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> hasAge.<span class="me1">getAge</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&gt;</span> <span class="nu0">16</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
List<span class="sy0">&lt;</span>Person<span class="sy0">&gt;</span> beerDrinkers <span class="sy0">=</span> filter<span class="br0">&#40;</span>persons, canDrinkBeer<span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
</blockquote>
<p>Then Cedric Beust <a href="http://beust.com/weblog/archives/000517.html">countered</a> with:</p>
<blockquote><h4>No loops</h4>
<p>Java is not very well suited to a functional style, so I think the first example is more readable than the second one that uses Predicates. I&#8217;m guessing most Java programmers would agree, even those that are comfortable with comprehensions and closures and especially those that aren&#8217;t.</p></blockquote>
<p>I guess this means I&#8217;m not &#8220;most Java programmers&#8221;.  Although I find the verbosity of the anonymous Predicate in Stephan&#8217;s code lamentable, aside from that I think the functional style is far superior.  And I don&#8217;t believe it should be seen as in any way at odds with &#8220;normal&#8221; Java style.  There&#8217;s no magic here: it&#8217;s just a straightforward anonymous class and filtering is a very simple concept to understand.  Conceptually it is no harder than the explicit loop: in fact it is easier as you know the higher purpose as soon as you see &#8220;filter&#8221;.</p>
<p>The higher level of abstraction is the key to its superiority.  Every non-trivial Java project will include many instances of searching, filtering, folding and so on of collections.  Repeating this most basic of logic time after time fills the code with mechanical details that hide its true purpose.  Why not get those details right once (in a library) and then never have to see them again?</p>
<p>In fact, once you embrace this style, things get even better.  Not only can you reuse basic operations like filtering, you can also:</p>
<ol>
<li><em>Compose</em> these operations to form even higher-level manipulations.</li>
<li>Build up a reusable set of functors (Predicates, Transforms, etc) instead of using anonymous classes.</li>
</ol>
<p>The latter point is important, as it allows you to remove an even more damaging sort of repetition &#8212; that of your project&#8217;s domain-specific logic.  Reduce Stephan&#8217;s example to:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">List<span class="sy0">&lt;</span>Person<span class="sy0">&gt;</span> beerDrinkers <span class="sy0">=</span> filter<span class="br0">&#40;</span>persons, <span class="kw1">new</span> CanDrinkBeerPredicate<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>and it is clearly superior.</p>
<p>Really, I think it is a shame to see Java programmers hesitant to use this style.  The ideas may come from the functional world, but there is nothing but basic Java code at work here.  The abstractions are both simple and powerful, which to me is the very definition of elegance.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2009/08/21/functional-vs-java-style/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Ready to Test: Maven + TestNG + Hamcrest + Mockito</title>
		<link>http://www.alittlemadness.com/2009/06/25/ready-to-test-maven-testng-hamcrest-mockito/</link>
		<comments>http://www.alittlemadness.com/2009/06/25/ready-to-test-maven-testng-hamcrest-mockito/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 23:12:49 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Build]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/?p=249</guid>
		<description><![CDATA[I&#8217;m no Maven fanboy, but for a new, small Java project the ultra-fast setup time is compelling.  So, for my latest little application, I decided to give it a go.  Sadly, the default Maven archetype lumped my project with JUnit 3.8.1.  Boo.  And although the TestNG website mentions an alternative archetype, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m no <a href="http://maven.apache.org">Maven</a> fanboy, but for a new, small Java project the ultra-fast setup time is compelling.  So, for my latest little application, I decided to give it a go.  Sadly, the default Maven archetype lumped my project with <a href="http://junit.org/">JUnit</a> 3.8.1.  Boo.  And although the TestNG website mentions an alternative archetype, it appears to have disappeared off the face of the internet.</p>
<p>Luckily, dragging my project into the present wasn&#8217;t difficult.  Along the way I also added my essential testing libraries: <a href="http://code.google.com/p/hamcrest/">Hamcrest</a> for matchers and <a href="http://code.google.com/p/mockito/">Mockito</a> for mocking (well, stubbing, but that&#8217;s another story).  For posterity&#8217;s sake, and for others that share my testing tastes, here&#8217;s how it&#8217;s done.</p>
<h2>Requirements</h2>
<p>I&#8217;m assuming that you have Maven 2 installed already.  If not, it&#8217;s trivial to:</p>
<ol>
<li><a href="http://maven.apache.org/download.html">Download</a> the latest (2.1.0 at time of writing); and</li>
<li>Install it according to the <a href="http://maven.apache.org/download.html#Installation">instructions</a> provided.
</ol>
<p>You can check if you have Maven ready to go by running:</p>
<div class="codesnip-container" >$ mvn &#8211;version<br />
Apache Maven 2.1.0 (r755702; 2009-03-18 19:10:27+0000)<br />
Java version: 1.6.0_12<br />
Java home: /usr/local/java/jdk1.6.0_12/jre<br />
Default locale: en_AU, platform encoding: UTF-8<br />
OS name: &#8220;linux&#8221; version: &#8220;2.6.28-11-generic&#8221; arch: &#8220;amd64&#8243; Family: &#8220;unix&#8221;</div>
<h2>Bootstrap</h2>
<p>With the lack of an available alternative, I found it easiest to start with the default archetype.  To create a new project, run something like:</p>
<div class="codesnip-container" >$ mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-app</div>
<p>Remember that if you&#8217;ve just installed Maven it will take this opportunity to <a href="http://fishbowl.pastiche.org/2007/12/20/maven_broken_by_design/">download the internet</a>.  Be patient.  If you&#8217;re new to Maven, you might also want to check out the <a href="http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html">5 minute guide</a> which walks through this in more detail.</p>
<p>Check that your bare application has been created:</p>
<div class="codesnip-container" >$ cd my-app<br />
$ find . -type f<br />
./src/main/java/com/mycompany/app/App.java<br />
./src/test/java/com/mycompany/app/AppTest.java<br />
./pom.xml<br />
$ mvn package<br />
&#8230;<br />
$ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App<br />
Hello World!</div>
<h2>Add the Dependencies</h2>
<p>Next you need to update the project POM to add the testing libraries as dependencies to your build.  This involves three changes:</p>
<ol>
<li>Removing the default dependency on JUnit.</li>
<li>Adding new dependencies for TestNG, Hamcrest and Mockito to the &#8220;test&#8221; scope.</li>
<li>Configuring the compiler to accept Java 5 source.</li>
</ol>
<p>The last step is necessary as the Maven default setting assumes Java 1.3 source, which apart from being ancient doesn&#8217;t support goodies such as annotations that are required for the new testing libraries.  Your updated pom.xml file should look something like:</p>
<div class="codesnip-container" >
<div class="xml codesnip" style="font-family:monospace;"><span class="sc3"><span class="re1">&lt;project</span> <span class="re0">xmlns</span>=<span class="st0">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="re0">xmlns:xsi</span>=<span class="st0">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span><br />
<span class="sc3"> &nbsp;<span class="re0">xsi:schemaLocation</span>=<span class="st0">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;modelVersion<span class="re2">&gt;</span></span></span>4.0.0<span class="sc3"><span class="re1">&lt;/modelVersion<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;groupId<span class="re2">&gt;</span></span></span>com.mycompany.app<span class="sc3"><span class="re1">&lt;/groupId<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;artifactId<span class="re2">&gt;</span></span></span>my-app<span class="sc3"><span class="re1">&lt;/artifactId<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;packaging<span class="re2">&gt;</span></span></span>jar<span class="sc3"><span class="re1">&lt;/packaging<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;version<span class="re2">&gt;</span></span></span>1.0-SNAPSHOT<span class="sc3"><span class="re1">&lt;/version<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>my-app<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;url<span class="re2">&gt;</span></span></span>http://maven.apache.org<span class="sc3"><span class="re1">&lt;/url<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;dependencies<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;groupId<span class="re2">&gt;</span></span></span>org.testng<span class="sc3"><span class="re1">&lt;/groupId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;artifactId<span class="re2">&gt;</span></span></span>testng<span class="sc3"><span class="re1">&lt;/artifactId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;version<span class="re2">&gt;</span></span></span>5.8<span class="sc3"><span class="re1">&lt;/version<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;scope<span class="re2">&gt;</span></span></span>test<span class="sc3"><span class="re1">&lt;/scope<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;classifier<span class="re2">&gt;</span></span></span>jdk15<span class="sc3"><span class="re1">&lt;/classifier<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;groupId<span class="re2">&gt;</span></span></span>org.mockito<span class="sc3"><span class="re1">&lt;/groupId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;artifactId<span class="re2">&gt;</span></span></span>mockito-all<span class="sc3"><span class="re1">&lt;/artifactId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;version<span class="re2">&gt;</span></span></span>1.8.0-rc2<span class="sc3"><span class="re1">&lt;/version<span class="re2">&gt;</span></span></span> <br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;scope<span class="re2">&gt;</span></span></span>test<span class="sc3"><span class="re1">&lt;/scope<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;groupId<span class="re2">&gt;</span></span></span>org.hamcrest<span class="sc3"><span class="re1">&lt;/groupId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;artifactId<span class="re2">&gt;</span></span></span>hamcrest-all<span class="sc3"><span class="re1">&lt;/artifactId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;version<span class="re2">&gt;</span></span></span>1.1<span class="sc3"><span class="re1">&lt;/version<span class="re2">&gt;</span></span></span> <br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;scope<span class="re2">&gt;</span></span></span>test<span class="sc3"><span class="re1">&lt;/scope<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/dependency<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/dependencies<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;build<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;plugins<span class="re2">&gt;</span></span></span> &nbsp;<br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;plugin<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;artifactId<span class="re2">&gt;</span></span></span>maven-compiler-plugin<span class="sc3"><span class="re1">&lt;/artifactId<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;configuration<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;source<span class="re2">&gt;</span></span></span>1.5<span class="sc3"><span class="re1">&lt;/source<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;target<span class="re2">&gt;</span></span></span>1.5<span class="sc3"><span class="re1">&lt;/target<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/configuration<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/plugin<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/plugins<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/build<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/project<span class="re2">&gt;</span></span></span></div>
</div>
<p>I&#8217;ve used the latest available versions of each of the libraries in this example &#8212; tweak them to suit your current reality.</p>
<h2>Update the Sample Test</h2>
<p>Now you&#8217;re ready to try updating the sample test case to use the trinity of TestNG, Hamcrest and Mockito.  The easiest way to do this is to get Maven to generate a project for your IDE, e.g.</p>
<div class="codesnip-container" >$ mvn eclipse:eclipse</div>
<p>or:</p>
<div class="codesnip-container" >$ mvn idea:idea</div>
<p>Fire up your chosen IDE, open the AppTest class, and edit it to exercise all of the dependencies:</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;"><span class="kw1">package</span> <span class="co2">com.mycompany.app</span><span class="sy0">;</span></p>
<p><span class="kw1">import</span> <span class="co2">static</span> org.<span class="me1">hamcrest</span>.<span class="me1">MatcherAssert</span>.<span class="me1">assertThat</span><span class="sy0">;</span><br />
<span class="kw1">import</span> <span class="co2">static</span> org.<span class="me1">hamcrest</span>.<span class="me1">Matchers</span>.<span class="me1">equalTo</span><span class="sy0">;</span><br />
<span class="kw1">import</span> <span class="co2">static</span> org.<span class="me1">mockito</span>.<span class="me1">Mockito</span>.<span class="me1">mock</span><span class="sy0">;</span><br />
<span class="kw1">import</span> <span class="co2">static</span> org.<span class="me1">mockito</span>.<span class="me1">Mockito</span>.<span class="me1">when</span><span class="sy0">;</span><br />
<span class="kw1">import</span> <span class="co2">org.testng.annotations.Test</span><span class="sy0">;</span></p>
<p><span class="kw1">import</span> <span class="co2">java.util.Random</span><span class="sy0">;</span></p>
<p><span class="kw1">public</span> <span class="kw1">class</span> AppTest <br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; @Test<br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">void</span> testApp<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Arandom+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Random</span></a> mockRandom <span class="sy0">=</span> mock<span class="br0">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Arandom+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Random</span></a>.<span class="kw1">class</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; when<span class="br0">&#40;</span>mockRandom.<span class="me1">nextInt</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="me1">thenReturn</span><span class="br0">&#40;</span>42<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; assertThat<span class="br0">&#40;</span>mockRandom.<span class="me1">nextInt</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, equalTo<span class="br0">&#40;</span>42<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>What are you waiting for?  Try it out:</p>
<div class="codesnip-container" >$ mvn test<br />
&#8230;<br />
Results :</p>
<p>Tests run: 1, Failures: 0, Errors: 0, Skipped: 0</p>
<p>[INFO] &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
[INFO] BUILD SUCCESSFUL<br />
[INFO] &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
[INFO] Total time: 18 seconds<br />
[INFO] Finished at: Wed Jun 24 16:11:48 BST 2009<br />
[INFO] Final Memory: 20M/100M<br />
[INFO] &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p></div>
<p>If you got this far, then everything you need is in place.  Now you just have to &#8230; implement your project!</p>
<h2>Extra Credit</h2>
<p>If you poke about a bit, you will also find that the maven surefire plugin, which manages the tests, generates some reports by default.  Along with HTML output, it also produces a JUnit-like XML report at:</p>
<div class="codesnip-container" >target/surefire-reports/TEST-TestSuite.xml</div>
<p>This report is ideal for integration with a continuous integration server (in my case <a href="http://zutubi.com/products/pulse/">Pulse</a>, naturally, but many will support it).</p>
<p>Happy testing! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2009/06/25/ready-to-test-maven-testng-hamcrest-mockito/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Devoxx: Future of the JVM</title>
		<link>http://www.alittlemadness.com/2008/12/12/devoxx-future-of-the-jvm/</link>
		<comments>http://www.alittlemadness.com/2008/12/12/devoxx-future-of-the-jvm/#comments</comments>
		<pubDate>Thu, 11 Dec 2008 21:02:14 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/2008/12/12/devoxx-future-of-the-jvm/</guid>
		<description><![CDATA[Today&#8217;s theme at Devoxx, at least from the talks I chose, was very much the future of the JVM, including the future of Java.  Two big things were highlighted: modularity and dynamism.
Modularity
The focus of JDK 7 will be a new module system for Java which will in turn be used to modularise the JDK [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s theme at <a href="http://www.devoxx.com/display/JV08/">Devoxx</a>, at least from the talks I chose, was very much the future of the JVM, including the future of Java.  Two big things were highlighted: modularity and dynamism.</p>
<h3>Modularity</h3>
<p>The focus of JDK 7 will be a new module system for Java which will in turn be used to modularise the JDK itself.  The plan is to develop the system in the open (no more JSR-277-style project management) as part of the recently-announced Project Jigsaw.  I encourage you to read Mark Reinhold&#8217;s <a href="http://blogs.sun.com/mr/entry/jigsaw">blog entry</a> for details.</p>
<p>One neat point that stood out for me was the desire to make this fit well with OS packaging systems (think RPMs, .debs, etc) &#8212; so it will be trivial to create an OS package for a Java module.  This should couple nicely with the easy availability of the Sun JDK on Linux these days (now it is open source), making Java software more integrated with the native platform.</p>
<p>A much more critical point, however, is the idea of versioning <em>as an enabler to make incompatible changes</em>.  Even as the news of <a href="http://cafe.elharo.com/programming/java-is-dead-long-live-python/">Java&#8217;s death</a> continues to roll in, it appears Sun is looking to put a mechanism in place that will allow them to finally make incompatible changes.  Once you have a modular JDK and the ability to express dependencies on particular versions of modules, it follows that it should be possible to make incompatible changes to those modules in new versions.  Perhaps in time this will allow a much-needed cleanup of the dark corners of the platform. </p>
<p>This also raises big questions for both <a href="http://osgi.org/">OSGi</a> and <a href="http://maven.apache.org/">Maven</a>.  I don&#8217;t expect either of these entrenched projects to disappear, but there is certainly overlap and a need to adapt.  On the OSGi front Sun is aiming for interoperability, but they claim that the Jigsaw module system will go down to a lower level than OSGi is capable (<strong>Update</strong>: it appears that this claim is controversial, see the comments below.).</p>
<h3>Dynamism</h3>
<p>Stepping away from Java the language and looking at the JVM platform, Brian Goetz and Alex Buckley spoke about the move &#8220;Towards a dynamic VM&#8221;.  The talk focused on the efforts in <a href="http://jcp.org/aboutJava/communityprocess/edr/jsr292/index.html">JSR-292</a> (aka the invokedynamic JSR) to make hosting dynamic languages on the JVM easier and more efficient.  The key component of this JSR is a new invokedynamic bytecode which can be used for dynamic method dispatch (when the actual method to call depends on more than just the type of the instance it is being invoked on).</p>
<p>The cool thing about invokedynamic is it will allow the various dynamic language runtimes to effectively plug method lookup functionality into the JVM.  This will allow each dynamic language implementation, many of which have very flexible method binding, to take full control of method selection.  This is key to efficient implementation of these languages on the JVM.</p>
<p>So hey, even if Java has lost its mojo, that isn&#8217;t the point anymore.  It&#8217;s the platform, stupid!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2008/12/12/devoxx-future-of-the-jvm/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Devoxx Conference Day 1</title>
		<link>http://www.alittlemadness.com/2008/12/11/devoxx-conference-day-1/</link>
		<comments>http://www.alittlemadness.com/2008/12/11/devoxx-conference-day-1/#comments</comments>
		<pubDate>Wed, 10 Dec 2008 22:07:57 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/2008/12/11/devoxx-conference-day-1/</guid>
		<description><![CDATA[Conference Day 1 (Devoxx Day 3) is done, and on balance it was decent, but hit-and-miss.  &#8220;Special guest&#8221; RoxorLoops &#8212; a Belgian Beatboxer &#8212; brought some variety to the opening.  He is a seriously talented guy and I think most enjoyed it as I did.
Of course the meat of the conference is the [...]]]></description>
			<content:encoded><![CDATA[<p>Conference Day 1 (Devoxx Day 3) is done, and on balance it was decent, but hit-and-miss.  &#8220;Special guest&#8221; RoxorLoops &#8212; a Belgian <a href="http://en.wikipedia.org/wiki/Beatboxing">Beatboxer</a> &#8212; brought some variety to the opening.  He is a seriously talented guy and I think most enjoyed it as I did.</p>
<p>Of course the meat of the conference is the talks.  Here&#8217;s a rundown of those that I attended:</p>
<ul>
<li><b>Keynote: JavaFX</b>: I have not taken much interest in JavaFX so far, so it was interesting to see a bit of it in action.  The most interesting part was the demo of dragging a JavaFX application out of a browser and having it run standalone.  It&#8217;s high on cool factor, and could be quite useful (though I doubt any user will think themselves to try it, so&#8230;).</li>
<li><b>Keynote: Java and RFID</b>: IBM and partners managed to take an interesting idea, namely running a live project at the conference tracking attendees with RFID, and turn it into a yawn-worthy presentation.  I kept wanting to see the actual software details behind it (not which RFID printers I can buy&#8230;).  When they did get to some software stuff, it felt like seriously over-engineered ADD (Acronym Driven Development).</li>
<li><b>From Concurrent to Parallel</b>: Brian Goetz gave a polished overview of the fork-join framework.  I&#8217;m into java.util.concurrent, so it&#8217;s good to get a look at the next logical step.</li>
<li><b>Effective Pairing: The Good, the Bad and the Ugly</b>: Dave Nicolette had previously done this talk with rehearsed players for various pairing scenarios.  As the players weren&#8217;t available, Dave took the ambitious route of getting audience volunteers to ad-lib instead.  It didn&#8217;t go too badly considering the obstacles (e.g. audio not set up for the job), but on balance it was probably too ambitious.  At least the audience did get involved, though.</li>
<li><b>The Feel of Scala</b>: this was my favourite of the day.  Bill Venners is a very clear speaker, and this talk was polished (perhaps done before).  I enjoyed the focus on real code samples, which were presented in an easily-followed fashion.  Bill&#8217;s own motivations for using Scala reminded me of my own desire to check it out, which I now plan to do more seriously than before.</li>
<li><b>Filthy Rich Android Clients</b>: I&#8217;m planning to get a G1 so thought I&#8217;d check out some eye candy.  Sadly, this talk was much too heavy on details and not enough on illustration.  Learning how things work is great, but packing slides full of points won&#8217;t do it &#8211; there needs to be more sample code/hands on work.  And this topic was just crying out for some eye-catching demos, of which there were too few in my opinion.</li>
<li><b>Jython</b>: Jythonistas Jim Baker and Tobias Ivarsson made a sometimes-awkward pairing for this talk.  They focused too much on Python and Django and not enough on Jython itself for my taste.  These are fine topics and we even use Django for <a href="http://zutubi.com/">zutubi.com</a>, but I was expecting more content about Jython and cool ways to leverage Python on the Java platform.  They did cover some of this territory, and get full marks for live coding and real demos.</li>
</ul>
<p>Oh, and free beer and frites is always a good way to end a day&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2008/12/11/devoxx-conference-day-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zutubi @ Devoxx 2008</title>
		<link>http://www.alittlemadness.com/2008/12/05/zutubi-devoxx-2008/</link>
		<comments>http://www.alittlemadness.com/2008/12/05/zutubi-devoxx-2008/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 00:43:20 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Zutubi]]></category>

		<guid isPermaLink="false">http://www.alittlemadness.com/2008/12/05/zutubi-devoxx-2008/</guid>
		<description><![CDATA[Next week I&#8217;ll be heading to Antwerp, Belgium for the 3 days of conference at Javapolis Javoxx Devoxx.  I don&#8217;t often go for larger conferences (too many marketroids), but have heard that Devoxx is a bit different &#8212; I guess I&#8217;ll find out!
I&#8217;m keen to hook up with any Zutubi customers, competitors or plain [...]]]></description>
			<content:encoded><![CDATA[<p>Next week I&#8217;ll be heading to Antwerp, Belgium for the 3 days of conference at <strike>Javapolis</strike> <strike>Javoxx</strike> <a href="http://www.devoxx.com/">Devoxx</a>.  I don&#8217;t often go for larger conferences (too many marketroids), but have heard that Devoxx is a bit different &#8212; I guess I&#8217;ll find out!</p>
<p>I&#8217;m keen to hook up with any Zutubi customers, competitors or plain old build/continuous integration geeks while I&#8217;m there, so drop me an <a href="mailto:jason@zutubi.com">email</a> if you&#8217;ll be there&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alittlemadness.com/2008/12/05/zutubi-devoxx-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

