<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>DogBiscuit</title>
    <description>... mmm, crunchy!</description>
    <link>http://dogbiscuit.org/mdub/weblog</link>
    <language>en-us</language>
    <generator>EvenYetAnotherWeblog</generator>
    <item>
      <title>TestGroups for JUnit</title>
      <guid>http://dogbiscuit.org/mdub/weblog/Tech/Programming/Java/TestGroupsForJUnit</guid>
      <pubDate>Sun, 19 Dec 2004 23:00:00 +1100</pubDate>
      <description><![CDATA[<p>
New users of <a href='http://www.junit.org'>JUnit</a> often assume that there will only
be one instance of their TestCase class (I did, at first).
</p>
<p>
In fact, each test-method is represented by a <a href='http://martinfowler.com/bliki/JunitNewInstance.html'>separate
instance</a> of the
test-class.  This isolation of test-methods is actually pretty sensible,
since it means that (from the <a href='http://junit.sourceforge.net/doc/cookstour/cookstour.htm'>horse's
mouth</a>)
</p>
<blockquote>
... each test will run with a fresh fixture and the results of one test
can't influence the result of another.
</blockquote>
<p>
If your tests are truly unit-tests, then re-creating a fresh fixture for
every method should be fairly cheap, so it's not a big deal.  BUT, it's a
slightly different story if you're using JUnit as a framework for
<em>acceptance</em> tests, or <em>integration</em> tests, or any scenario in which
creating the required fixture/resource objects is costly.
</p>
<h3>
My problem
</h3>
<p>
On my current project, we have a large suite of web-app acceptance-tests
written using <a href='http://dogbiscuit.org/mdub/weblog/Tech/Programming/Java/htmlunit.sourceforge.net'>HtmlUnit</a>.  We starting off writing
tests something like this:
<pre>
public PolicySelectionScreenTest extends TestCase {
    public void setUp() throws Exception {
        expensiveSetUpCode();
    }
    public void testPolicyTypeDefaultsToStandard() {
        assertEquals(&quot;STD&quot;, screenFixture.getPolicyType());
    }
    public void testWindscreenOptionDefaultsToNo() {
        assertEquals(&quot;N&quot;, screenFixture.getWindscreenOption());
    }
}
</pre>
</p>
<p>
It soon became obvious that re-running the
<code>expensiveSetUpCode()</code> for each test was - well - expensive, so
we starting looking for ways to reduce that overhead.  An obvious way to do
it is to bundle several asserts into the one test, e.g.
<pre>
public PolicySelectionScreenTest extends TestCase {
    public void testInitialScreenStateIsCorrect() {
        expensiveSetUpCode();
        assertEquals(&quot;STD&quot;, screenFixture.getPolicyType());
        assertEquals(&quot;N&quot;, screenFixture.getWindscreenOption());
    }
}
</pre>
</p>
<p>
There are a couple of problems with this, though:
</p>
<ul>
<li>
Test-methods get bloaty, and their names become less informative.  This
  isn't ideal, as I prefer short test-methods, with names that describe the
  intended behaviour.
</li>
<li>
Testing of a scenario may halt prematurely, when it could usefully run
  further and provide more feedback about what is or isn't working.
</li>
</ul>
<h3>
A solution
</h3>
<p>
So, I developed a way of aggregating a number of related test-methods into
a "TestGroup".  Now our tests look more like this:
<pre>
public PolicySelectionScreenTests extends TestGroup {
    public void groupSetUp() throws Exception {
        expensiveSetUpCode();
    }
    public void testPolicyTypeDefaultsToStandard() {
        assertEquals(&quot;STD&quot;, screenFixture.getPolicyType());
    }
    public void testWindscreenOptionDefaultsToNo() {
        assertEquals(&quot;N&quot;, screenFixture.getWindscreenOption());
    }
}
</pre>
</p>
<p>
A <tt>TestGroup</tt> instance can be converted into JUnit-ese easily, by calling
its <code>asTest()</code> method:
<pre>
public static Test suite() {
    TestSuite suite = new TestSuite();
    // ... etc ...
    suite.addTest(new PolicySelectionScreenTests().asTest());
    return suite;
}
</pre>
</p>
<p>
Alternatively, we have an extended <tt>TestSuite</tt> implementation that makes
this a little easier:
<pre>
public static Test suite() {
    TestSuite suite = new GroupAwareTestSuite();
    // ... etc ...
    suite.addTestSuite(PolicySelectionScreenTests.class);
    return suite;
}
</pre>
</p>
<p>
Now, our original tests run faster (since the
<code>expensiveSetUpCode()</code> is only run once), but the test-methods
remain short and well-named.  Woo-hoo!  [cue weird little dance of joy].
</p>
<h3>
But wait, there's more
</h3>
<p>
As you might have guessed, there's a <code>groupTearDown()</code> to match
<code>groupSetUp()</code>.  The normal <code>setUp()</code> and
<code>tearDown()</code> hooks are also supported, and run before/after each
test, as you'd expect.
</p>
<h3>
A warning
</h3>
<p>
Once we start sharing test-fixtures like this, we're effectively removing
JUnit's built-in safety harness, and thus running the risk of tests
infecting the results of other tests by "polluting" the fixture.  There's
no easy solution: you just have to <em>be really careful</em>.  Guidelines:
</p>
<ul class="sparse">
<li>
If possible, avoid putting any code that alters the state into the
  test-methods of a TestGroup.
</li>
<li>
If that's not possible, ensure you reset the fixture to a known state in
  the <code>setUp()</code> hook.
</li>
</ul>
<h3>
A peek inside
</h3>
<p>
In my first attempt at TestGroups, I simply implemented the
<a href='http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Test.html'><tt>Test</tt></a>
interface.  Unfortunately, it's a fairly thin interface, and doesn't
provide an API for navigating the hierarchical structure of a test-suite.
If you want to explore the hierarchy, you'll have to assume that your
test-suite will be constructed from <tt>TestCase</tt> and <tt>TestSuite</tt> objects -
perhaps with the odd <tt>TestDecorator</tt> thrown in - and perform the required
<tt>instanceof</tt> checks.  If some new, unknown implementation of <tt>Test</tt> comes
along, your assumptions are shot.  Most IDEs are in this position, as they
typically display the test-hierarchy.  Thus, my original implementation
didn't play nicely in an IDE environment.
</p>
<p>
So, instead, <code>TestGroup.asTest()</code> creates a structure that
adapts the <tt>TestGroup</tt> to look like a <tt>TestSuite</tt>.  The suite is wrapped by
a <tt>TestSetup</tt> decorator that fires the <code>groupSetUp()</code> and
<code>groupTearDown()</code> hooks.  The <tt>TestCases</tt> in the suite are
simple proxies that invoke methods on the shared <tt>TestGroup</tt> instance.  Or,
in pictures:
</p>
<p>
<img src="/mdub/images/TestGroup-asTest.gif" alt="TestGroup">
</p>
<p>
Because the result is just a aggregate of core JUnit objects, it doesn't
confuse IDEs in the way I described earlier.
</p>
<h3>
The code
</h3>
<p>
If you're interested in using <tt>TestGroups</tt>, or just want to take a look at the
code, you can get it <a href='/mdub/software/testgroups-src.jar'>here</a>.
</p>
]]></description>
    </item>
  </channel>
</rss>
