C.R.A.P. metrics for Grails

This is a quick how-to post on getting Change Risk Anti-Patterns statistics for your Grails code.

Firstly thanks to Jeff Winkler for bringing the new GMetrics v0.5 CrapMetric to my attention and thanks to Chris Mair for his great work on GMetrics (and Codenarc).

What is Change Risk Anti-Patterns?

It is a method to analyze and predict the amount of effort, pain, and time required to maintain an existing body of code. Given a Java method m, C.R.A.P. for m is calculated as follows:
C.R.A.P.(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
Where comp(m) is the cyclomatic complexity of method m, and cov(m) is the test code coverage provided by automated tests.
For more background information see this blog post describing the C.R.A.P. metric.

Setting up Grails

This is very fresh so you’ll need to do a little bit of tinkering until I can get the following changes incorporated into the GMetrics plugin!
Note you’ll also need to have the Code Coverage plugin installed (refer to “Grails & Hudson Part 3: Testing” for more details on that).

Install the GMetrics plugin

This is the straightforward bit:
grails install-plugin gmetrics

The hackery

With GMetrics plugin version 0.3.1 you’ll need to edit the installed plugin dependencies.groovy (e.g. ~/.grails/1.3.7/projects/foo/plugins/gmetrics-0.3.1/dependencies.groovy) to use gmetrics 0.5 instead of 0.3.
Line 27 should be changed to:

provided('org.gmetrics:GMetrics:0.5') {

And you’ll want to modify scripts/gmetrics.groovy to use metricSetFile on the Ant task otherwise it will just use the default metrics which doesn’t include C.R.A.P.
e.g. line 44 should become:


Define a metric set

We now need to tell GMetrics which metrics to run – out of laziness I saved this in the root of the Grails project as test.gmetrics:

import org.gmetrics.metric.cyclomatic.CyclomaticComplexityMetric

final COBERTURA_FILE = 'file:target/test-reports/cobertura/coverage.xml'

  metricset {
    def cyclomaticComplexityMetric = metric(CyclomaticComplexityMetric)

    def coberturaMetric = CoberturaLineCoverage {
      coberturaFile = COBERTURA_FILE
      functions = ['total']

    CRAP {
      functions = ['total']
      coverageMetric = coberturaMetric
      complexityMetric = cyclomaticComplexityMetric

Configure the plugin

If you want the HTML report, then your Config.groovy will need a single addition to specify the metric set:

gmetrics.metricSetfilename = 'file:test.gmetrics'

If you want an XML report you’ll also need:

gmetrics.outputFile = 'target/test-reports/GMetricsReport.xml'
gmetrics.reportType = 'org.gmetrics.report.XmlReportWriter'

Let’s go

Now it’s all configured, we just need to ensure that we have coverage data before we run the CrapMetric.

grails test-app -unit -coverage -xml

We can now run:
grails gmetrics

The report will be generated and the plugin output will state where it has been written to. The CRAPpy threshold has been defined as 30 – so the report will help to highlight the areas of code that you need to concentrate on first.

Remember that over complex code with full test coverage can still be classed as CRAPpy.


One response to “C.R.A.P. metrics for Grails

  1. Wow, that was fast! Thanks for this series of posts by the way. I’ve gotten so many great ideas from them. Fantastic stuff.

    I’m running unit/integration tests and Codenarc in 1st pass build (will break build if new violations). Deploy/functional tests in another, with promoted builds.

    Cobertura seems to really slow down the build, so I tend to put it in a downstream project. Probably could be run nightly or even weekly. It’d be great to visualize with CrapMap πŸ™‚ — http://schneide.wordpress.com/2009/06/15/a-guide-through-the-swamp-the-crapmap/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s