If you are trying to test Grails domain class constraints by putting your unit test cases in the 'test/unit' directory, then your tests will fail because the domain objects will not have the 'valdate' method. This can be resolved in two ways:
What follows is some example code around this finding.
I am working on a Groovy on Grails project for a website to help programmers keep up and refresh their skills.
I started with some domain classes and then moved on to write some unit tests. When we create a Grails project using
it creates several directories, one of which is a directory called 'test' for holding unit tests. This directory contains two directories, 'unit', and 'integration' for unit and integration tests respectively.
Now begins an interesting journey with writing unit tests in Groovy. I wanted to write tests for my domain classes. A simple domain class like the one I have below can contain only properties and constraints for those properties. This is what Trail.groovy looks like.
I wanted to start writing unit tests to test the constraints. When Grails creates a domain class, it injects several methods in it at runtime , one of which is a method called 'validate'. This method is called before the domain object is saved and it will return a false if the domain object has violated any constraints. So, I created a simple unit test to test the constraints of Trail.groovy
This is what my initial test case looked like.
When I ran my tests using
(See how well Grails integrated testing), I got a bunch of errors that told me that the 'validate' method was not found. If you enjoy looking at stack traces... feast your eyes:
After some Googling I realized that the 'validate' method is injected into domain objects by the Grails framework, and therefore it does not exist when we instantiate the domain object from test code. I later found that if a test is placed inside 'test/integration' then the test cases are created as the objects would have been created by the Grails framework. So the domain objects would have the 'validate' method. But I also read in another place (I cannot remember where), that if possible it is k better to mock these special methods instead of putting tests in the integration directory, since these tests take longer to instantiate and can slow down the overral running time. And I found in yet another place that there exists a method called 'mockForConstraintsTests(Trail)' which will inject the 'validate' method along with some other methods. So, I added this mock method to my setup after which I was able to run my tests successfully.
The rest of the class is the same.
So to summarize, if you are trying to test constraints in Grails domain classes, you have two options:
- Place the test cases inside test/integration (which will slow things down)
- Use the method 'mockForConstraintsTests(Trail)' to create mock method in your domain class and continue writing your test cases in 'test/unit'
What follows is some example code around this finding.
I am working on a Groovy on Grails project for a website to help programmers keep up and refresh their skills.
I started with some domain classes and then moved on to write some unit tests. When we create a Grails project using
grails create-app,
it creates several directories, one of which is a directory called 'test' for holding unit tests. This directory contains two directories, 'unit', and 'integration' for unit and integration tests respectively.
Now begins an interesting journey with writing unit tests in Groovy. I wanted to write tests for my domain classes. A simple domain class like the one I have below can contain only properties and constraints for those properties. This is what Trail.groovy looks like.
class Trail {
String shortName
String name
String description
def hasMany = [learningObjects:LearningObject]
static constraints = {
shortName(maxSize:6, blank:false)
name(maxSize:75, blank:false)
description(maxSize:2048, blank:false)
}
}
I wanted to start writing unit tests to test the constraints. When Grails creates a domain class, it injects several methods in it at runtime , one of which is a method called 'validate'. This method is called before the domain object is saved and it will return a false if the domain object has violated any constraints. So, I created a simple unit test to test the constraints of Trail.groovy
This is what my initial test case looked like.
import grails.test.*
class TrailTests extends GrailsUnitTestCase {
def trail
protected void setUp() {
super.setUp()
trail = new Trail(shortName:'sname',
name:'Java 101',
description:'This is a basic Java course')
}
protected void tearDown() {
super.tearDown()
}
void testShortNameConstraints() {
assertTrue(trail.validate())
trail.shortName = 'thisisaverylongname'
assertFalse(trail.validate())
trail.shortName = ''
assertFalse(trail.validate())
}
//... further methods not shown
}
When I ran my tests using
grails test-app
(See how well Grails integrated testing), I got a bunch of errors that told me that the 'validate' method was not found. If you enjoy looking at stack traces... feast your eyes:
Testcase: testShortNameConstraints took 0.159 sec
Caused an ERROR
No signature of method: Trail.validate() is applicable for argument types: () values: []
groovy.lang.MissingMethodException: No signature of method: Trail.validate() is applicable for argument types: () values: []
at TrailTests.testShortNameConstraints(TrailTests.groovy:20)
at _GrailsTest_groovy$_run_closure4.doCall(_GrailsTest_groovy:203)
at _GrailsTest_groovy$_run_closure4.call(_GrailsTest_groovy)
at _GrailsTest_groovy$_run_closure2.doCall(_GrailsTest_groovy:147)
at _GrailsTest_groovy$_run_closure1_closure19.doCall(_GrailsTest_groovy:113)
at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:96)
at TestApp$_run_closure1.doCall(TestApp.groovy:66)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy:480)
After some Googling I realized that the 'validate' method is injected into domain objects by the Grails framework, and therefore it does not exist when we instantiate the domain object from test code. I later found that if a test is placed inside 'test/integration' then the test cases are created as the objects would have been created by the Grails framework. So the domain objects would have the 'validate' method. But I also read in another place (I cannot remember where), that if possible it is k better to mock these special methods instead of putting tests in the integration directory, since these tests take longer to instantiate and can slow down the overral running time. And I found in yet another place that there exists a method called 'mockForConstraintsTests(Trail)' which will inject the 'validate' method along with some other methods. So, I added this mock method to my setup after which I was able to run my tests successfully.
protected void setUp() {
super.setUp()
mockForConstraintsTests(Trail)
trail = new Trail(shortName:'sname',
name:'Java 101',
description:'This is a basic Java course')
}
The rest of the class is the same.
So to summarize, if you are trying to test constraints in Grails domain classes, you have two options:
- Place the test cases inside test/integration (which will slow things down)
- Use the method 'mockForConstraintsTests(Trail)' to create mock method in your domain class and continue writing your test cases in 'test/unit'
Comments
i have the same problem when testing domain classes.
I tried your solution with mock object but i receive the same error.
The only way i was able to run the test was to move all the files into the integration folder.
have you find any other ways to solve this?
Do you get the exact same error?
--
Parag
http://www.adaptivelearningonline.net
i got the same error
No signature of method: Person.save() is applicable for argument types: () values: []
groovy.lang.MissingMethodException: No signature of method: Person.save() is applicable for argument types: () values: []
at PersonTests.testSomething(PersonTests.groovy:14)
at _GrailsTest_groovy$_run_closure4.doCall(_GrailsTest_groovy:203)
at _GrailsTest_groovy$_run_closure4.call(_GrailsTest_groovy)
at _GrailsTest_groovy$_run_closure2.doCall(_GrailsTest_groovy:147)
at _GrailsTest_groovy$_run_closure1_closure19.doCall(_GrailsTest_groovy:113)
at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:96)
at TestApp$_run_closure1.doCall(TestApp.groovy:66)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy:480)
I use grails 1.1.2 and java6
It's strange all the grails tutorials i found don't mention this problem.
--
Regards
Parag
Earlier someone posted a comment about the 'mockForConstraintsTests' method not working for them.
Perhaps they were using the GroovyTestCase instead of GrailsUnitTestCase.
thnx
It has been a while since I have worked on Grails, so I am not aware of the recent set of good tutorials or books. Their website has some links which might be useful to get started
http://grails.org/Tutorials