8.8 Generating JUnitPerf Tests

8.8.1 Problem

You want to use JUnitPerfDoclet, which is an XDoclet code generator created specifically for this book, to generate and execute JUnitPerf tests.

8.8.2 Solution

Mark up your JUnit test methods with JUnitPerfDoclet tags and execute the perfdoclet Ant task.

8.8.3 Discussion

As we were writing this book, we came up with the idea to code-generate JUnitPerf tests to show how to extend the XDoclet framework. This recipe uses that code generator, which is aptly named JUnitPerfDoclet, to create JUnitPerf tests. The concept is simple: mark up existing JUnit tests with JUnitPerfDoclet tags and execute an Ant target to generate the code.

8.8.3.1 Creating a timed test

Here is how to mark up an existing JUnit test method to create a JUnitPerf TimedTest:

/**
 * @junitperf.timedtest maxElapsedTime="2000"
 *                      waitForCompletion="false"
 */
public void testSynchronousSearch(  ) {
        // details left out
}

The @junitperf.timedtest tag tells JUnitPerfDoclet that it should decorate the testSynchronousSearch( ) method with a JUnitPerf TimedTest.

The maxElapsedTime attribute is mandatory and specifies the maximum time the test method is allowed to execute (the time is in milliseconds) or the test fails.

The waitForCompletion attribute is optional and specifies when a failure should occur. If the value is "true", the total elapsed time is checked after the test method completes. A value of "false" causes the test to fail immediately if the test method exceeds the maximum time allowed.

8.8.3.2 Creating a load test

Here is how to mark up an existing JUnit test method to create a JUnitPerf LoadTest:

/**
 * @junitperf.loadtest numberOfUsers="100"
 *                     numberOfIterations="3"
 */
public void testAsynchronousSearch(  ) {
    // details left out
}

The @junitperf.loadtest tag tells JUnitPerfDoclet that it should decorate the testAsynchronousSearch( ) method with a JUnitPerf LoadTest.

The numberOfUsers attribute is mandatory and indicates the number of users or threads that simultaneously execute the test method.

The numberOfIterations attribute is optional. The value is a positive whole number that indicates how many times each user executes the test method.

8.8.3.3 Generating the code

Example 8-6 shows how to generate the tests. First, a new task definition is created, called perfdoclet. This task is responsible for kick-starting the code generation process. We exclude from the fileset any class that begins with "TestPerf" because there may be hand-coded JUnitPerf tests somewhere in the source tree. Finally, the junitperf subtask creates a new JUnitPerf class for each JUnit test case class that contains at least one test method with JUnitPerfDoclet tags. For example, if a JUnit test case class named TestSearch uses JUnitPerfDoclet tags, then the generated JUnitPerf test class is named TestPerfTestSearch.

Example 8-6. JUnitPerfDoclet setup
<target name="generate.perf"
    depends="prepare"
    description="Generates the JUnitPerf tests.">
  <taskdef name="perfdoclet" classname="xdoclet.DocletTask">
    <classpath>
      <pathelement location="${dir.lib}/oreilly-junitperf-module.jar"/>
      <pathelement location="${dir.lib}/commons-logging-1.0.jar"/>
      <pathelement path="${env.JUNIT_HOME}/junit.jar"/>
      <pathelement path="${env.XDOCLET_HOME}/lib/xdoclet.jar"/>
      <pathelement path="${env.XDOCLET_HOME}/lib/xjavadoc.jar"/>
    </classpath>
  </taskdef>

  <perfdoclet
      destdir="${dir.generated.src}">

    <fileset dir="${dir.src}">
      <include name="**/junitperf/Test*.java"/>
      <exclude name="**/junitperf/TestPerf*.java"/>
    </fileset>

    <junitperf destinationFile="TestPerf{0}.java"/>
  </perfdoclet>
</target>

Example 8-7 shows how to execute the performance tests using the junit task. Remember that this book uses the naming convention "TestPerf" to represent JUnitPerf tests.

Example 8-7. Executing JUnitPerf tests with Ant
<target name="junitperf"
    depends="generate.junitperf,compile.generated"
    description="Runs the JUnitPerf tests.">
  <junit printsummary="on" fork="false" haltonfailure="false">
    <classpath refid="classpath.project"/>
    <formatter type="plain" usefile="false"/>
    <batchtest fork="false" todir="${dir.build}">
      <fileset dir="${dir.generated.src}">
        <include name="**/TestPerf*.java"/>
      </fileset>
    </batchtest>
  </junit>
</target>

8.8.4 See Also

The last few recipes in Chapter 9 discuss how to extend the XDoclet framework to generate JUnitPerf tests. A good starting point is Recipe 9.9.