• Home
  • RSS Feed
  • Log in

Helpful error messages in Grails
Posted by Erik Pragt around lunchtime: May 4th, 2008

Currenttly, I'm in the process of building a Grails application. While I've built several prototypes/quick hacks, this is actually the first 'real' application I'm building. "So", I thought, "if this is a real application, I'm in need of some real tests!". When you're in the normal flow of developing a Grails application, everything goes so fast, you almost forget about writing the tests. So I decided to do it a bit differently, and do it just like in Java: do it TDD!

The problem

I've currently created a small domain model. On of the classes in the domain is called a task, which looks something like this:

 
class Task {
    String title
    String description
 
    static constraints = {
        title(blank: false)
        description(blank: true)
    }
}
 

As you can see here, I've create a small class with 2 properties, of which the description is optional. Now, I'd like to know if my validation is correct, so I've created a testcase.

In Grails, there's a difference between integration testing and unit testing. The integration tests startup the whole Grails container, inject your domain classes with the proper GORM methods, etc, etc, while the unit tests don't: they're just quick functional tests.

The testcase looks like this:

 
void testCreateTask() {
  assertNotNull new Task(description: 'This is a task').save()
}
 

Running this test ('grails run-app') gives me the following output:

-------------------------------------------------------
Running 1 Integration Test...
Running test com.xebia.domain.TaskTest...
--Output from testCreateProject--
testCreateTask...FAILURE
Integration Tests Completed in 719ms
-------------------------------------------------------

Hmm, my test fails. But why? Oh, I see, I forgot to add a title to my task. But where is my error message? Grails validation knows what went wrong, but why do I only see a FAILURE in the log?

What happens, is that Grails creates a HTML report containing the tests and their respective output. When opening the report, you see something like the picture below:

Grails HTML report

Alas, no details on why the test fails! The only information given by the stacktrace is the line on which the test failed: 23, but no further information on why the test failed.


N/A
junit.framework.AssertionFailedError
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:226)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:899)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:946)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:77)
at com.xebia.domain.TaskTest.testCreateTask(GrailsProjectServiceTest.groovy:23)

Like I said above, in this case it's easy: just add a title, and the test will work. But when using some more complex behaviour, it might be a bit harder to find out what went wrong. Because I couldn't find a proper solution in the Grails documentation, I decided to create my own solution.

Solution

What I did to 'fix' this problem, was to define a new method, named 'assertValid'. This method (closure actually) checks if the supplied argument is valid, and if it isn't, it will collect the error messages associated with the object and display then in an assert statement.

This results in the following code:

 
GroovyTestCase.metaClass.assertValid << { object ->
  println "assertValid"
  def validate = object.validate()
  def message = object.errors.allErrors.inject('') {str, error ->
    str + "Field error in object ${error.objectName} on field ${error.field}: rejected value [${error.rejectedValue}];"
  }
 
  assertTrue message, validate
  assertNotNull object.save()
}
 

What I did here, was use Groovy's ExandoMetaClass facility here to dynamically add a method to GroovyTestCase, which is the class all tests extend from. The assertValid method is added to it, and is now available for use in all instances of the GroovyTestCase. This means I can now do the following:

 
void testCreateTask() {
  Task task = new Task(description: 'This is a task')
  assertValid task
}
 

Running this will ofcourse still produce an error, but instead of giving an 'N/A' as message, the test report will now display the following:


Field error in object com.xebia.domain.Task on field title: rejected value [null];

Conclusion

So, by leveraging some of Grails Spring power, and the Groovy MetaClass facility, it was quite easy to get some detailed information about the failures in the Grails domain binding, and in a very reusable way! I hope you've found this blog useful, and if you've any comments, don't hessitate and let me know!

  • Share/Bookmark

Tags: Grails, Testing
Filed under Grails, Groovy, Java, Testing | 2 Comments »



2 Responses to “Helpful error messages in Grails”



    Age Mooy Says:
    Posted at: May 4, 2008 at 1:24 pm

    Nice workaround that shows off the metaclass magic. But this a basically a very irritating bug in Grails. Have you submitted a bug or a feature request ?



    Erik Pragt Says:
    Posted at: May 4, 2008 at 4:06 pm

    Hi Age, while I agree it’s suboptimal, I find it a bit farstreched to call it a bug. It just more work to get the right information.

    I will post this a feature request when I’m sure I haven’t overlooked anything in the Grails documentation.



Leave a Reply

Click here to cancel reply.

Deployment automation for Java application running on Websphere, WebLogic and JBoss

Archives

  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009

Xebia Sites

  • Xebia Corporate
  • Xebia France
  • Xebia India

Categories

  • Java (282)
  • Agile (109)
  • General (50)
  • Testing (42)
  • Performance (42)
  • Hibernate (36)
  • Scrum (33)
  • Podcast (31)
  • Architecture (31)
  • Spring (28)
  • SOA (24)
  • Maven (22)
  • Project Management (22)
  • Middleware (23)
    • Deployment (14)
  • Flex (17)
  • JPA (17)
  • Eclipse (15)
  • Xebia Labs (15)
  • Quality Assurance (14)

Tag Cloud

    Scala Maven product owner JavaOne SOA Performance Ajax Poppendieck Groovy fitnesse Testing Agile Semantic Web Scrum IntelliJ Closures Xebia Agile Awareness Workshop Introduction to Agile XML esb Java Hibernate Grails qcon Lean Architecture Spring Seam Functional Programming