我正在使用Grails 2.3.8并尝试为使用服务的过滤器创建单元测试。
过滤器:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
规范,第一次尝试:
@TestFor(ExecutionTraceController)
@Mock(LicenseFilters)
class LicenseFiltersSpec extends Specification{
void "Test filter redirects when license is wrong"() {
given:
LicenseFilters bean=applicationContext.getBean("com.nortia.sgmentia.license.LicenseFilters")
bean.licenseService=this.buildLicenseServiceStub(false)
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok){
LicenseService result=Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
但事实证明(通过调试)我从上下文中获取的bean 它不是相同的接收请求,因此我仍然获得NPE
在第二次尝试中,我尝试使用 defineBeans :
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean){
targetObject = this
targetMethod= "buildLicenseServiceStub"
arguments=[false]
}
}
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
但是被嘲笑的豆子既不是豆子也不是诅咒。
我是否应该尝试将服务手动进入过滤器? 有这个问题https://jira.grails.org/browse/GRAILS-8976但它已关闭。
答案 0 :(得分:0)
我终于找到了一种解决方法,使其能够使用第二种方法(使用defineBeans)。
该服务未被自动连接到过滤器中,因此我最终手动使用伪单例:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!this.licenseService){
this.licenseService=applicationContext.getBean("licenseService")
}
if(!this.licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
相当难看,但至少是一个解决方案。 希望它可以帮助那些人。
答案 1 :(得分:0)
我遇到了类似的情况,并且能够通过将服务添加到@Mock注释来修复它,即@Mock([LicenseFilters, LicenseService])
。
在您的情况下,规范将类似于以下内容:
@TestFor(ExecutionTraceController)
@Mock([LicenseFilters, LicenseService])
class LicenseFiltersSpec extends Specification {
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean) {
targetObject = this
targetMethod = "buildLicenseServiceStub"
arguments = [false]
}
}
when:
withFilters(action: "list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok) {
LicenseService result = Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
注意:默认情况下,以这种方式模拟服务会将实际LicenseService的实例注入您的过滤器。因此,如果删除了上面的defineBeans块,则将调用LicenseService.checkLicense()的实际实现。