March 2007

Sketching complexity with Groovy

Not long ago, I wrote up a nifty dashboarding application, à la Groovy, in an effort to abate the visual pain associated with report overload syndrome. These kinds of applications are perfect for languages like Groovy as you can knock them out in a matter of hours (including a test suite to verify kosherness).

One of the applications which adds to an increase in the number of reports one must digest is JavaNCSS. This disco tool analyzes a code base and reports everything relating to code length, including class sizes, method sizes, and the number of methods found in a class. What’s more, JavaNCSS reports method complexities, Cyclomatic style.

While all this data is helpful in some scenarios, it is probably too much to digest at a glace, man. For example, the report generated via Ant is shown to the right. That’s a lot of data, don’t you think?

Interestingly, one scenario came to mind that the data from JavaNCSS could provide– what is the distribution of complexity across the entire code base? Because it’s my bag, this actually can be helpful in understanding, at a high level, what’s going on. A “healthy” code base would not have a high degree of highly complex methods; consequently, a highly complex code base would have a high number of complex methods.

Yet, the default report generated via Ant doesn’t really tell this story– while the data is there, it doesn’t stand out. What’s needed is a visual guide that quickly demonstrates the distribution of complexity– in this case, something like a bar chart would work just fine.

Before a chart can be generated; however, the data needs to be mined. This is where Groovy comes in. Via its copasetic built-in XML parsing, I can quickly get all the data I need to understand the distribution of complexity. For example, I was interested in five different ranges of complexity:

  • Methods with a CCN of 1
  • Methods with a CCN between 2 and 5
  • Methods with a CCN between 6 and 10
  • Methods with a CCN over 10 but less than or equal to 20
  • Everything greater than 20

These ranges could, of course, vary depending on what you’re trying to understand. In my case, I wanted to get a feel for the number of really simple methods (like getters and setters) and constructors (which JavaNCSS treats just like normal methods by reporting CCN). A healthy code base, in the Age of Aquarius, would probably have the majority of its methods falling within the first two buckets and hopefully not have any data in the last two. The middle one may have a few methods here and there.

Obtaining the method complexity distribution in a JavaNCSS XML report via Groovy is absurdly simple as this code snippet shows:

def range1 = 2..5
def range2 = 6..10
def range3 = 11..20

this.doc.functions.function.each{ mthd ->
 int ccn = Integer.parseInt(mthd.ccn.text())

 if(ccn == 1){
  ones << mthd.name.text()
 }else if (range1.contains(ccn)){
  low << mthd.name.text()
 }else if(range2.contains(ccn)){
  medium << mthd.name.text()
 }else if(range3.contains(ccn)){
  midMax << mthd.name.text()
 }else{
  max << mthd.name.text()
 }
}

Using Groovy’s range feature, I can define some simple ranges that correspond with my desired distribution. Plus, in a closure that iterates over each function element in the JavaNCSS XML document, I can obtain the element ccn’s value and place it within the proper collection via the handy << syntax.

With this hip data, I can then feed it to a charting utility, like JFreeChart, and generate a bar chart like so:

dataset.addValue(val1 * 100, disdta[0].name, disdta[0].name)
dataset.addValue(val2 * 100, disdta[1].name, disdta[1].name)
dataset.addValue(val3 * 100, disdta[2].name, disdta[2].name)
dataset.addValue(val4 * 100, disdta[3].name, disdta[3].name)
dataset.addValue(val5 * 100, disdta[4].name, disdta[4].name)

def chart = ChartFactory.createBarChart(
 "Complexity Distribution",
 "CCN Range",
 "% Total Methods",
 dataset,
 PlotOrientation.VERTICAL,
 false,
 false,
 false
)

In this snippet the val variables above are each multiplied by 100 to create a percentage value (i.e 66%). In earlier code, the total number of methods is obtained (i.e. 22,334) and each obtained collection value is divided by this number to create a ratio (i.e. 543/22,334). What’s more, after creating the chart instance, you can customize various aspects of the chart like its colors, etc. For example, to change the five bar’s colors, you can obtain a BarRenderer instance from the chart’s plot instance and set the series color as follows:

def rendr = plot.getRenderer()

rendr.setSeriesPaint(0, new Color(102,205,000))
rendr.setSeriesPaint(1, new Color(000,100,000))
rendr.setSeriesPaint(2, new Color(255,215,000))
rendr.setSeriesPaint(3, new Color(255,140,000))
rendr.setSeriesPaint(4, new Color(139,000,000))

Lastly, you can save the chart instance to a file too like so:

ChartUtilities.saveChartAsPNG(
  new File("C:\\dev\\projects\\acme\\target\\mc.png"),
    chart, 375, 200)                            

The resulting bar chart is shown to the right and displays the distribution of complexity across all methods within a code base. In this case, this code base has roughly 55% of its methods with a CCN of 1, man. One could infer that there are a lot of smokin’ JavaBean style classes, which in this case is true. A small portion of methods, unfortunately do have some high complexity values, which does cause some concern.

Of course, this is only a partial picture, right? This bar chart doesn’t tell me anything about the associated coverage of those complex methods and it’s only a snap shot in time, man– tomorrow, if this utility is run and the far right bar grew, you’d know that things are getting worse.

As you can see, Groovy is an excellent choice for generating simple reports as you can knock them out in a snap. Plus, by building intelligent charts, you can further help save people from report overload syndrome. Dig it?

The weekly bag– March 23

Nine links in this week’s bag:

The weekly bag– March 16

Because it’s my bag, it’s yours now:

Cosmopolitan fixtures in TestNG

As I’ve written about before, TestNG supports parametric testing quite copaseticly; in fact, not only can you obtain parameters for tests, but TestNG also supports parametric fixtures. This means you can effectively create generic fixture objects that tailor themselves to particular environments.

For example, because it’s my bag, I often find myself needing a hip DbUnit fixture to handle managing a state of a database during testing; however, in order for DbUnit to work, at a minimum, you must provide:

  • a database driver to load
  • a connection URL
  • the database user
  • the database password
  • a path to a seed file

DbUnit uses the first 4 aspects to connect to a database, which it’ll seed with the contents found in item #5. These 5 items are often hard coded in testing scenarios; however, with TestNG’s smokin’ parametric fixtures, you can force the actual values to be defined at test time by placing them into TestNG’s testng.xml file.

First I can define a cosmopolitan DbUnit fixture like so:

public class DatabaseFixture {

 @Parameters({"seed-path","db-driver","db-url","db-user","db-psswrd"})
 @BeforeTest
 public void seedDatabase(String seedpath, String driver,
   String url, String user, String pssword) throws Exception {
  IDatabaseConnection conn =
     this.getConnection(driver, url, user, pssword);
  IDataSet data = this.getDataSet(seedpath);
  try {
   DatabaseOperation.CLEAN_INSERT.execute(conn, data);
  }finally {
   conn.close();
 }
}

private IDataSet getDataSet(String path) throws IOException,
 DataSetException {
  return new FlatXmlDataSet(new File(path));
}

private IDatabaseConnection getConnection(String driver, String url,
  String user, String pssword ) throws ClassNotFoundException,
   SQLException {
  Class.forName(driver);
  Connection jdbcConnection =
   DriverManager.getConnection(url, user, pssword);
  return new DatabaseConnection(jdbcConnection);
 }
}

Note how the tripping 5 items listed earlier are now parameters to this fixture via the Parameters annotation, which decorates the seedDatabase method. Wiring actual values to these parameters is done via the parameter element, which can be placed in TestNG’s testng.xml file as follows:

<suite name="Acceptance Tests">

 <parameter name="seed-path" value="test/conf/seed.xml"/>
 <parameter name="db-driver" value="org.hsqldb.jdbcDriver"/>
 <parameter name="db-url" value="jdbc:hsqldb:hsql://127.0.0.1"/>
 <parameter name="db-user" value="foo"/>
 <parameter name="db-psswrd" value="bar"/>

 <test name="CRUDs" >
  <packages>
   <package name="test.org.acme.web" />
   <package name="test.org.acme.web.fixtures" />
  </packages>
 </test>
</suite>

With these parameters defined in TestNG’s configuration file, I can now vary their values at runtime for different environments by defining different test groups within the testng.xml file– or, I can even use Ant’s replace task to replace these values with environment specific values. Either way, using TestNG’s parametric fixtures is a sure fire way to create generic fixtures that can be reused in different scenarios easily, man! Dig it?

.NET productivity just got scary

About a year ago, I started looking deeply into boo, which is a Python inspired language targeting the .NET CLI that enables rapid development of compliant Windows applications. With boo, you can quickly write developer tests, build GUIs, prototype applications– you name it– this language is frighteningly simple, man. Check out InfoQ’s “Much ado about Boo” and see for yourself how with its relaxed syntax, boo is a convenient platform for doing just about anything on the .NET platform quickly.

The weekly bag– March 9

Broad themes in this week’s bag– enjoy:

Easily validate GUI components with TestNG-Abbot

As I’ve written about before, TestNG-Abbot is a newly minted testing framework that breathes new life into testing GUI components. If you are currently writing or maintaining Swing or AWT applications, then check out developerWorks‘ “Automate GUI testing with TestNG-Abbot” and you see how surprisingly easy it is to isolate GUI components and then verify them using TestNG-Abbot’s handy fixture objects.

As always, don’t forget to Swing (no pun intended) over to the “Improve Your Java Code Quality” forum and let it all hang out, man!

The weekly bag– March 2

Because it’s my bag, baby: