August 2006

Early performance testing with JUnitPerf

Verifying application performance is almost always a secondary concern during application development. Mind you, I’m stressing the verification of application performance, man. An application’s performance is always a chief concern from day one, but rarely is it verified until much, much later.

There are a number of copasetic reasons why performance testing is put off until it later cycles; however, in my experience, it seems most businesses don’t truly take application performance testing seriously because they don’t know what to expect. Of course, numbers are thrown out in the beginning stages; however, reality is almost always different– either the application performs much lower than expected or things take off like wild fire.

Performance testing usually becomes a primary concern once two square things happen:

  • there is a noticeable performance problem in production
  • a customer or prospective customer demands to know performance numbers

There is an easy way; however, to ascertain basic low level performance numbers using existing JUnit assets. Via the JUnitPerf framework, existing JUnit tests can be quickly turned into simple load tests and even stress tests.

JUnitPerf can create two types of hip tests using the decorator pattern– TimedTests and LoadTests using JUnit’s suite mechanism. TimedTests create a top level bound for a test case– if this time is surpassed then the test fails. LoadTests work in cooperation with timers and create an artificial load on a particular test case by running it a desired amount of times separated by the configured timer.

For example, the TimedTest below will run the testToXML test case once and if this test case takes longer than 170 milliseconds the test case will fail.

public static Test suite() {
 long maxElapsedTime = 170; //170 milliseconds
 Test testCase = new BatchDepXMLReportPerfTest("testToXML");
 //passing false to this constructor would fail the
 //test immediately if test exceeded 170ms
 //otherwise this test finishes and is failed if > 170ms
 Test timedTest = new TimedTest(testCase, maxElapsedTime);
 return timedTest;
}

In the suite method below, a LoadTest is defined, which will run the testFindVerifyDefinition test case 10 times, each thread launching every 100 milliseconds.

public static Test suite() {
 int users = 10;
 Timer timer = new ConstantTimer(100);
 return new LoadTest(
  new WordDAOImplLoadTest("testFindVerifyDefinition"),
    users, timer);
}

Using this keen framework, basic performance measures can be put into place, which can give a baseline breaking limit on low level application code, such as:

  • how long it takes for the executeTrade method to complete
  • how long does it take for this same method to complete under various load scenarios

Plus, this framework can reuse your existing JUnit tests that already verify the executeTrade method! What a trip!

Copasetic code reviews

Two copasetic articles were recently published that cover the code review process; however, they each take a different tact. In “Code Reviews“, Srivaths Sankaran elaborates on a suggested manual process, while acknowledging that it’s next to impossible to review every last hip line of code. A great companion article is Paul Duvall’s “Automation for the people: Continuous Inspection“, which proposes using automated tools like PMD or CheckStyle to enhance manual reviews as those tools focus on low-level details. Accordingly, in person code reviews can focus on higher level aspects of code, such as design, or as Srivaths points out validating business requirements.

Neat-o tools like PMD also make it easy to spot code which should be reviewed. Because complexity metrics, like Cyclomatic complexity, strongly correlate to defects, if PMD flags a method with excessive values, taking the time to figure out why the complexity is there and determining if there is a path to mitigate it will almost certainly pay dividends in the future. Dig it?

TestNG parametric testing

One hip feature available in TestNG is the capability to run parametric tests. By placing parametric data in TestNG’s XML configuration files, a single test case can, in essence, be reused with different data sets, which can even provide different results.

You can delineate a parametric test via the parameters annotation, which maps parameter names to values via copasetic suite files. For example, here is a parametric test containing two parameters– classname, which is of type String and size, which is an int.

/**
 * @testng.test
 * @testng.parameters value="class_name, size"
 */
public void assertValues(String classname, int size) throws Exception{
 Hierarchy hier = HierarchyBuilder.buildHierarchy(classname);
 assert hier.getHierarchyClassNames().length == size: "didn't equal!";
}

Parameter values are defined in TestNG’s XML suite files– so for above test, I can map two values to classname and sizejava.util.Vector and 2.

<suite name="ambr8">
 <test name="ambr8-test">
  <parameter name="class_name" value="java.util.Vector"/>
  <parameter name="size" value="2"/>
  <classes>
   <class name="test.com.acme.da.HierarchyTest"/>
  </classes>
 </test>
</suite>

When I run this test, java.util.Vector and 2 will be passed to this test method by the TestNG framework. The beauty here is that non-programmers can start to get involved too, by providing thier own data values. This, by the way, is also a groovy way to avoid tests that only assert sunny-day scenarios or don’t effectively perform bounds checking, man.

Without this feature, to test 4 variations on parameter values, you’d need to write at least 4 tests, right? Now, you can write one generic test and pull the data values into a more human friendly format, which happens to be similar to the Fit model. Dig it?

Running Groovy tests in Java

As I’ve mentioned before, JUnit tests written in Groovy (against a Java application) are sometimes easier to write than in plain-Jane Java because of Groovy’s relaxed syntax. And fewer imports, fewer type declarations, and no semi-colons are just the tip of the iceberg too, man.

Running Groovy JUnit tests through an existing build process managed by Ant or Maven is simple too- especially when a project already has existing hip Java JUnit tests. Ideally, in this scenario, the difference between a Java test and a Groovy one should be seamless- having two different tasks that run each platform’s tests seems like overkill- why not run the Groovy ones with the Java ones?

Groovy bundles a TestSuite type dubbed AllTestSuite, which facilitates running Groovy JUnit scripts from within an IDE and of course, a build process that already runs normal Java JUnit tests. The copasetic class works by looking for System properties which delineate where Groovy tests reside and a naming pattern (such as tests/groovy and **/*Test.groovy).

What I find most effective; however, is to create my own dynomite TestSuite type, set the System properties in a static block and then override the suite method and call AllTestSuite’s suite like so:

package test.com.acme.sda;

import groovy.util.AllTestSuite;
import junit.framework.Test;
import junit.framework.TestSuite;

public class AllGroovySuite extends TestSuite {	

 static {
  System.setProperty(AllTestSuite.SYSPROP_TEST_DIR, "./test/groovy");
  System.setProperty(AllTestSuite.SYSPROP_TEST_PATTERN, "**/*Test.groovy");
 }

 public static void main(String[] args) {
  junit.textui.TestRunner.run(AllTestSuite.suite());
 }	

 public static Test suite() {
  return AllTestSuite.suite();
 }
}

Note how AllGroovySuite is written in normal Java and provides values for Groovy’s AllTestSuite’s SYSPROP_TEST_DIR and SYSPROP_TEST_PATTERN. When this class is run via a JUnit runner, the SYSPROP_TEST_DIR directory is scanned and any file matching the SYSPROP_TEST_PATTERN pattern is loaded by AllTestSuite and run.

By adopting this technique, I can run Groovy test scripts in an IDE, like Eclipse (and of course, see the green bar); furthermore, existing test tasks in Ant or goals in Maven can pick this class up and run it (which then runs all Groovy tests). Pretty groovy, eh?

Podcasts that boogie

If you:

  • Want to learn more about Continuous Integration
  • Live to disco dance
  • Still watch reruns of Saturday Night Fever
  • Are curious about Test Categorization
  • Use the word “copasetic” in everyday conversations

then you’ll have a hip time listening to these two podcasts:

In the Age of Aquarius disco never dies man. Dig it?