New version of Code Coverage plugin released

January 30, 2008 – 6:21 am

I released an updated version of the code coverage plugin for Grails today. This release incorporates some of the suggestions others have offered in the last few days:

  • renamed the “test-app-coverage” script to “test-app-cobertura” - perhaps in the future we will add another code coverage library (EMMA?) to the plugin so users can choose which they would like to run
  • Added a “-xml” option for the command line. By default, the plugin will generate HTML reports. If you would like and XML report (e.g. for a continuous integration server), run the command like this: grails test test-app-cobertura -xml
  • Added a dependency check for the grails version in the plugin file. The script was written against Grails 1.0-final-SNAPSHOT and it’s not backwards compatible with previous versions of Grails (sorry).
  • Added some metadata to the plugin file (title, description, etc) so the information appears correctly when you do a grails list-plugins

Another bug was raised - when you run the script, Grails sets the environment to “development” by default. This may be OK if your DEV and TEST datasource definitions are the same - but if they’re not, please run the script with the grails environment set to test. As far as I know you can do this one of two ways:

  • grails test test-app-cobertura
  • grails -Dgrails.env=test test-app-cobertura

The plugin source is now available in the Grails plugins SVN repository. You can install it by running grails install-plugin code-coverage or by downloading the zip file from here: http://plugins.grails.org/grails-code-coverage/trunk/grails-code-coverage-0.3.zip

Branch you say? What branch?

January 27, 2008 – 8:46 pm

When I use Cobertura to instrument my Grails Controllers, it doesn’t seem to accurately report on the branch coverage. For instance, the index closure in my controller looks like this:

1
2
3
def index = {
	redirect(action:list,params:params)
}

The tests look like this:

1
2
3
4
5
6
7
8
9
10
void testIndex(){
	stateController.index()
	assertEquals('/state/list', stateController.response.redirectedUrl)
}
 
void testIndexWithParams(){
	stateController.params.max=10
	stateController.index()
	assertEquals('/state/list?max=10', stateController.response.redirectedUrl)
}

I don’t believe there are actually two possible branches to that little line of code with the redirect (line 2 in the first code example), but Cobertura reports only 1 of 2 branches is covered. What do you think is the elusive second branch? Apparently I’m not the only one with that question - I found this post on the Groovy users mailing list, but no solution.

In fact, the entire class apparently has some issues with the branch coverage:

For me this may not be a huge deal since I’m mostly using this report as a guide to highlight areas of code that aren’t covered at all by tests. But it would be nice to not have simple lines of code (where branch coverage should really be N/A) highlighted in red on the report.

If you’re interested, here are the Controller and the Test - I think it should be pretty close to 100% covered for both line and branch.

Using coverage reports for better tests

January 26, 2008 – 2:34 pm

After creating a Cobertura Plugin for Grails, I thought I’d give it a test run on some simple domain class logic and tests. Consider this example in grails-app/domain:

1
2
3
4
5
6
7
8
9
10
11
12
class State {
	String name
	String postalCode
 
	def isMinnesota(){
		return 'MN' == postalCode
	}
 
	def isWisconsin(){
		return 'WI' == postalCode
	}
}

The two helper methods (isMinnesota and isWisconsin) deserve some tests:

1
2
3
4
5
6
7
8
9
void testIsMinnesota() {
	state.postalCode = 'MN'
	assertTrue('should be true when state is MN', state.isMinnesota())
}
 
void testIsWisconsin() {
	state.postalCode = 'WI'
	assertTrue('should be true when state is WI', state.isWisconsin())
}

Looks good, right? When I run grails test-app-coverage and look at the reports, there is 100% line coverage, but the branch coverage is only 50%:

The tests didn’t take into account the case in which the state is NOT Minnesota or NOT Wisconsin. Just modify the test cases to add some assertions:

1
2
3
4
5
6
7
8
9
10
11
12
13
void testIsMinnesota() {
	state.postalCode = 'NOT mn'
	assertFalse('should be false when state is not MN', state.isMinnesota())
	state.postalCode = 'MN'
	assertTrue('should be true when state is MN', state.isMinnesota())
}
 
void testIsWisconsin() {
	state.postalCode = 'NOT wi'
	assertFalse('should be false when state is not WI', state.isWisconsin())
	state.postalCode = 'WI'
	assertTrue('should be true when state is WI', state.isWisconsin())
}

And run the reports again:

And now there’s 100% line coverage AND 100% branch coverage - perfect.

Test Code Coverage in a Grails app with Cobertura

January 26, 2008 – 1:18 pm

I’ve always liked having code coverage reports to help me find branches of code that aren’t being tested. On the past couple of Java projects I’ve worked on we used Ant and Cobertura to generate those reports. It turns out that compiled Groovy code can also be instrumented by Cobertura. That got me to thinking about how this could be done on a Grails application.

So I downloaded Cobertura and started writing a Gant script to utilize it in my Grails application. Basically, I wanted to create a wrapper around the TestApp.groovy script that comes with Grails, calling several existing Gant targets to compile and run the tests, with some new targets to instrument the test classes and generate a coverage report. I figured the default target would look something like this:

1
2
3
4
5
6
7
8
9
target ('default': "Test App with Coverage") {
    depends( classpath, checkVersion, configureProxy, packagePlugins )
    cleanup()
    packageApp()
    compileTests()
    instrumentTests() // new target to instrument the classes
    testApp()
    coberturaReport() // new target to generate code coverage reports
}

After a little trial and error, I created a new Gant script (TestAppCoverage.groovy) and got it working. There were a couple workarounds I had to deal with - for example, normally, you fork the test run so that Cobertura can flush the coverage results when the JVM halts. In this case, I didn’t have that luxury so I had to explicitly tell Cobertura to “flush” the coverage results while the JVM was still active (luckily there is an entry at the end of the Cobertura FAQ on how to do this).

Once I had that figured out, the Cobertura Report task couldn’t find the source to display on the HTML report pages. I think Cobertura interprets sub directories as packages, so I couldn’t specify the source directory as ‘grails-app’. Instead, I had to call out each directory individually to provide a ‘flat’ file set to Cobertura, i.e.

1
2
3
4
5
6
7
8
9
10
11
Ant.'cobertura-report'(destDir:"${coverageReportDir}", datafile:"${dataFile}"){
    //load all these dirs independently so the dir structure is flattened,
    //otherwise the source isn't found for the reports
    fileset(dir:"${basedir}/grails-app/controllers")
    fileset(dir:"${basedir}/grails-app/domain")
    fileset(dir:"${basedir}/grails-app/services")
    fileset(dir:"${basedir}/grails-app/taglib")
    fileset(dir:"${basedir}/grails-app/utils")
    fileset(dir:"${basedir}/src/groovy")
    fileset(dir:"${basedir}/src/java")
}

Another issue was where to put the instrumented classes AND have that directory come before the testClasses directory in the classpath. I tried to figure that one out, but eventually decided to reuse the testClasses directory for the instrumented classes. I don’t think this is ideal, but it was easier than figuring out classpath ordering (call me lazy). Also, I had to delete the test classes each test run and re-instrument them in order to get accurate results. This adds some time to the whole process, but new changes didn’t seem to get picked up correctly if I didn’t.

TestApp.groovy calls exit(0) when it finishes - and so the new coberturaReport() target would never get called. Thanks to a tip from Graeme I was able to override the ‘exit’ target in the TestAppCoverage.groovy script:

1
2
3
4
5
6
target('exit':"override exit") { def code ->
    //ignore '0' exit code to bypass TestApp.groovy exiting, process any other return code
    if (0 != code){
        System.exit(code)
    }
}

Finally, I decided that this would actually best be implemented as a plugin, rather than just another script in the ’scripts’ directory of my application. Just download this Grails Cobertrua Plugin zip file (UPDATE: new version released!) to your project directory, then call grails install-plugin grails-cobertura-0.1.zip to install it. Run grails test-app-coverage and check out the reports (reports are placed in test/reports/cobertura).

Give it a shot, and let me know if you have any suggestions on how to improve the TestAppCoverage.groovy script!

Create a simple Tag Library in Grails

September 12, 2007 – 6:00 pm

I presented a quick and dirty introduction to Tag Libraries at the Groovy Users Group of MN this week. It’s a little contrived (I’m not sure you would actually write a tag to do this), but it shows how to build a simple tag library and also how to test it. This example uses Grails version 0.6 and the full source for the example can be downloaded here.

Setup the domain model

grails create-app bookstore
cd bookstore
grails create-domain-class Book
grails create-domain-class Author
grails create-domain-class Translation

Edit the domain classes and add some properties:
Author.groovy

class Author {
	String name
}

Translation.groovy

class Translation {
	String language
}

Book.groovy

class Book {
	String title
	static hasMany = [authors:Author, translations:Translation]
}

Bootstrap some data
conf/BootStrap.groovy

class BootStrap {
     def init = { servletContext ->
		def book = new Book(title:"Guide to Tag Libraries")
		book.addToAuthors(new Author(name:'Mike'))
		book.addToAuthors(new Author(name:'Robin'))
		book.addToTranslations(new Translation(language:'English'))
		book.addToTranslations(new Translation(language:'Spanish'))
		book.save()
     }
     def destroy = {
     }
}

Generate scaffolding and run the app

grails generate-all Author
grails generate-all Translation
grails generate-all Book
grails run-app

Browse to http://localhost:8080/bookstore/book/show/1

By default, Grails uses the toString() method to label the associated Authors and Translations, e.g. “Author : 1″
Generated scaffolding code for grails-app/views/book/show.gsp:

<tr class="prop">
	<td valign="top" class="name">Authors:</td>
	<td  valign="top" style="text-align:left;" class="value">
		<ul>
		<g:each var="a" in="${book.authors}">
			<li><g:link
				controller="author"
				action="show"
				id="${a.id}">${a}</g:link>
			</li>
		</g:each>
		</ul>
	</td>
</tr>

Create a tag library to display associated properties

grails create-tag-lib Bookstore

Edit the generated file at grails-app/taglib/BookstoreTagLib.groovy. As a first pass, create a closure that outputs a line item utilizing the toString() method of each item in the collection

class BookstoreTagLib {
	def eachInCollection = { attrs ->
		attrs['collection'].each{
			out << "<li>${it}</li>"
		}
	}
}

Edit the generated scaffolding code for grails-app/views/book/show.gsp to utilize the taglib

<td  valign="top" style="text-align:left;" class="value">
	<ul>
		<g:eachInCollection collection="${book.authors}"/>
	</ul>
</td>

Refresh http://localhost:8080/bookstore/book/show/1

Enhance the closure in the tag library to accept an optional attribute called “property” to display something more meaningful than “Author: 1″, i.e. display the “name” property instead…

class BookstoreTagLib {
	def eachInCollection = { attrs ->
		def propertyName = attrs['property']
		attrs['collection'].each{
			if (propertyName){
				out << "<li>${it[propertyName]}</li>"
			} else {
				out << "<li>${it}</li>"
			}
		}
	}
}

Modify show.gsp to pass the “property” parameter

<g:eachInCollection collection="${book.authors}" property="name"/>

Refresh http://localhost:8080/bookstore/book/show/1

Sample Unit Test
It’s easy to do assertions - invoking the closure on the taglib returns a String which can compared against an expected return value
test/integration/BookstoreTagLibTests.groovy

class BookstoreTagLibTests extends GroovyTestCase {
	def taglib
	def book
 
	void setUp(){
		taglib = new BookstoreTagLib()
		book = new Book()
	}
 
	void testEachInCollectionNoPropertyName() {
		book.addToAuthors(new Author(id:1))
		assertEquals("<li>Author : 1</li>",
			taglib.eachInCollection([collection: book.authors]))
	}
 
	void testEachInCollectionPropertyName() {
		book.addToAuthors(new Author(name:'UnitTest1'))
		assertEquals("<li>UnitTest1</li>",
			taglib.eachInCollection([collection: book.authors, property:'name']))
	}
 
}

Enhance the tag library further to support linking - by calling an existing tag library as a method!
Add a new closure in grails-app/taglib/BookstoreTagLib.groovy

def linkEachInCollection = { attrs ->
	def propertyName = attrs['property']
	def controllerName = attrs['controller']
	attrs['collection'].each{
		def prop
		if (propertyName){
			prop = it[propertyName]
		} else {
			prop = it.id
		}
		out << "<li>" +
			link([controller:controllerName, action:'show', id:it.id]){prop} +
			"</li>"
	}
}

Change tag being called in show.gsp to linkEachInCollection

<g:linkEachInCollection collection="${book.authors}" property="name" controller="author"/>

Refresh http://localhost:8080/bookstore/book/show/1
Now the list of authors are linked!

Apply the tag library change to the Translations collection in show.gsp:

<g:linkEachInCollection collection="${book.translations}"
property="language" controller="translation"/>

Refresh http://localhost:8080/bookstore/book/show/1
Now the list of translations have meaningful labels and are linked!

Built in tag libraries
Don’t forget that Grails already has many built in tag libraries - see http://grails.codehaus.org/Tag+Library+Reference for more details.