更新
@Ramsharan 下面的答案是正确的。这可以说是 Grails 本身的一个缺陷,但肯定是一个文档问题。我向 Grails Jira 添加了缺陷报告 https://jira.grails.org/browse/GRAILS-11595 。我还将测试代码(包括修复)添加到了 GitHub:https://github.com/xnickmx/grails-2.4.2-plugin-integration-test-example
原始问题:
注意:如果我创建应用程序而不是插件,则这一系列步骤将有效。概述
我的 Grails 插件项目有一个尝试创建域类的服务方法。从集成测试中调用服务的方法会导致
java.lang.IllegalStateException: Method on class [Domain class] was used outside of a Grails application.
背景
- 在 Windows 7 上运行的 Grails 版本 2.4.2
- 从头开始创建一个插件项目(例如:GrailsTestPlugin)
- 创建一个简单的域类(示例:Person)
- 使用创建域类实例的方法(示例:createPerson)创建一个简单的服务类(示例:PersonService)
- 创建调用服务类方法的集成测试(示例:PersonServiceITSpec)
- 运行测试并获得 NullPointerException。症状与 GRAILS-10538 非常相似(但这个错误提到了单元测试,据说已经修复)。在应用程序和插件项目中都会以这种方式失败。
- 将服务的 @Transactional 注释更改为 static transactional = true 并再次运行测试。这次测试失败了
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)
如果我将服务类更改为不再尝试创建域类实例,它就会起作用。
发生了什么事?
这看起来像是基本的 Grails 功能。我很惊讶它似乎不适用于插件项目。难道我做错了什么?这不应该起作用吗?这是一个错误吗?
详细信息
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 org.grails.testplugin.service.PersonServiceITSpec
内容:
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())
}
}
运行测试
grails test-app integration:
最佳答案
由于您正在运行集成测试,因此不需要为服务执行new
。你的测试应该是这样的
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
}
}
框架会自动在该字段中注入(inject) personService,并且它不应该是私有(private)的。
我宁愿扩展 IntegrationSpec
,而不是扩展 Specification
类。
更新:
错误原因是缺少hibernate插件。 当我们创建新插件时,hibernate插件不会添加到插件依赖项中。因此包含域的测试会产生问题。所以添加
运行时“:hibernate4:4.3.5.4”//或“:hibernate:3.6.10.16”
在插件依赖项的 BuildConfig.groovy 中。它可能看起来像这样
插件{
构建(“:发布:3.0.1”,
“:rest-client-builder:1.0.3”){
导出=假
}
运行时 ":hibernate4:4.3.5.4"//或 ":hibernate:3.6.10.16"
}
改变hibernate的范围来测试可能会更好。
关于grails - Grails 插件服务与 GORM 的集成测试应该有效吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24815173/