@Ramsharan's answer below is correct. This is arguably a defect in Grails itself, but certainly a documentation problem. I added a defect report to the Grails Jira https://jira.grails.org/browse/GRAILS-11595. I also added the test code (including fix) to GitHub: https://github.com/xnickmx/grails-2.4.2-plugin-integration-test-example
My Grails plugin project has a service method that attempts to create a domain class. Calling the service's method from an integration test results in a
java.lang.IllegalStateException: Method on class [Domain class] was used outside of a Grails application.
java.lang.IllegalStateException: Method on class [org.grails.testplugin.domain.Person] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly. at org.grails.testplugin.service.PersonService.createPerson(PersonService.groovy:13)
If I change my service class to no longer attempt to create a domain class instance, it works.
This seems like basic Grails functionality. I'm surprised it doesn't seem to work in plugin projects. Am I doing something wrong? Is this not supposed to work? Is it a bug?
org.grails.testplugin.domain.Person.groovy:
package org.grails.testplugin.domain
class Person {
String name
static constraints = {
}
}
org.grails.testplugin.service.PersonService:
package org.grails.testplugin.service
import grails.transaction.Transactional
import org.grails.testplugin.domain.Person
//@Transactional have to comment out to avoid NPE
class PersonService {
static transactional = true
Person createPerson(String name) {
new Person(name: name).save()
}
}
Create integration test:
create-integration-test org.grails.testplugin.service.PersonServiceITSpec
contents:
package org.grails.testplugin.service
import spock.lang.*
import static org.junit.Assert.*
/**
* Tests PersonService
*/
class PersonServiceITSpec extends Specification {
private PersonService personService
def setup() {
personService = new PersonService()
}
def cleanup() {
}
void "test createPerson happy path"() {
given:
final name = "name"
when:
final result = personService.createPerson(name)
then:
assertNotNull(result)
assertEquals(name, result.name)
assertNotNull(result.getId())
}
}
Run the tests
grails test-app integration:
Since you are running integration test, you do not need to do new
for service. Your test should be something like this
import spock.lang.*
class PersonServiceITSpec extends Specification {
PersonService personService
def setup() {
}
def cleanup() {
}
void "test createPerson happy path"() {
given:
final String name = 'name'
when:
def result = personService.createPerson(name)
then:
result != null
name == result.name
result.id != null
}
}
The framework will automatically inject personService in the field and it should not be private.
Instead of extending Specification
class, I would prefer extending IntegrationSpec
.
UPDATE:
The reason for the error is the missing of hibernate plugin. When we create new plugin, hibernate plugin is not added in plugin dependency. So the test which contains domain will create problem. So add
runtime ":hibernate4:4.3.5.4" // or ":hibernate:3.6.10.16"
in BuildConfig.groovy in plugins dependency. It may look like this
plugins {
build(":release:3.0.1",
":rest-client-builder:1.0.3") {
export = false
}
runtime ":hibernate4:4.3.5.4" // or ":hibernate:3.6.10.16"
}
It may be better to change the scope of hibernate to test.