带有模拟服务的单元测试过滤器

时间:2014-11-21 13:19:09

标签: unit-testing grails service filter

我正在使用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但它已关闭。

2 个答案:

答案 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()的实际实现。