【问题标题】:grails spock testing failing with 'java.lang.IllegalArgumentException: ServletContext must not be null'grails spock 测试因“java.lang.IllegalArgumentException:ServletContext 不能为空”而失败
【发布时间】:2014-10-23 09:40:01
【问题描述】:

我在command class 中有一个方法,它使用messageSource.getMessage(...),因为messageSource 不会被注入commandClass。我用

def messageSource = Holders.applicationContext.getBean("messageSource") 在commandClass 内。

我的问题是在尝试写unit test这个方法时,

@Before
void setup() {
    Holders.applicationContext.getBean("messageSource")
}

void "testFunction"() {
    //inside testFunction I am using messageSource
    given:
        //required things
    when:
        //call the function
    then:
        //assert
}

测试此功能后,我得到了错误

java.lang.IllegalArgumentException: ServletContext must not be null at grails.util.Holders.getApplicationContext(Holders.java:80)

有人可以建议如何解决这个问题。

更新

@Validateable
class commandClass {
    //required fields and constraints
    def formatData(List<commandClass> commandObjs) {
        StringBuilder validationErrors
        commandObjs.each {commandObj->
            validationErrors = new StringBuilder()
            if(commandObj.hasErrors()) {
                commandObj.errors.allErrors.each {it ->
                    validationErrors.append(messageSource.getMessage(it, null)).append('\n')
                }
            }
            commandObj.metaClass.validationErrors = validationErrors
        }

    }
} 

提前致谢

【问题讨论】:

  • 请提供问题中的Command类?

标签: java grails spock


【解决方案1】:

我找到了答案

void setup() {
    mockApplicationContext()
}

def static mockApplicationContext() {
    GrailsUnitTestMixin.initGrailsApplication()
    Holders.grailsApplication = GrailsUnitTestMixin.grailsApplication
    Holders.metaClass.'static'.getApplicationContext = { ->
        return GrailsUnitTestMixin.applicationContext
    }
    Holders.metaClass.applicationContext.getBean = { bean ->
        return GrailsUnitTestMixin.messageSource
    }
}

我稍后会更新更多关于答案的信息

【讨论】:

    【解决方案2】:

    ============更新答案========================

    现在我正在使用 grails 2.4.2。

    这里不需要使用Holders.applicationContext.getBean("messageSource")获取messageSource,会自动注入。

    那么Command对象的例子:

    @Validateable
    class Test {
        def messageSource
        String aa
    
        static constraints = {
        aa blank:false, validator: {val, obj ->
                println obj.messageSource.getMessage("default.paginate.prev",null,LocaleContextHolder.locale)
                ...
            }
        ...
    

    测试示例:

    void "test for valid data"() {
        when:
        def test = new Test(aa:'hello')
        def messageSource = Mock(MessageSource)
        test.messageSource = messageSource
        then:
        test.validate()
    }
    

    您也可以使用 mockFor 来代替 Mock。

    =========老答案============

    您可以在Command object 中使用service 并将messageSource 包装在service 中,而不是直接使用messageSource。

    服务示例:

    class I18nMessageService {
        MessageSource messageSource
    
        def getMessage(String code, Object[] args=null) {
            messageSource.getMessage(code,args,LocaleContextHolder.locale)
        }
    }
    

    Command对象的例子:

    @Validateable
    class Test {
        def i18nMessageService
        String aa
    
        static constraints = {
            aa blank:false, validator: {val, obj ->
                println obj.i18nMessageService.getMessage("default.paginate.next")
                ...
            }
        }
    }
    

    在运行应用程序时,i18nMessageService 会自动注入到 Test 命令对象。

    为了测试,应该手动模拟和注入 i18nMessageService。

    测试示例:

    void "test for valid data"() {
        when:
        def test = new Test(aa:'hello')
        def i18nMessageServiceMock = mockFor(I18nMessageService)
        i18nMessageServiceMock.demand.getMessage {'message you wanted'}
        test.i18nMessageService = i18nMessageServiceMock.createMock()
        then:
        test.validate()
    }
    

    【讨论】:

    • 谢谢你的回答,我们可以直接使用MessageSource,只在命令类里面对吧?
    • 您使用哪个版本的 grails?
    • grails 2.3.8 版本
    • 好的谢谢,让我试试
    • 我也在签入2.3.8版本。
    【解决方案3】:

    如果你使用的是 Grails 3,你只需添加注解

    @TestMixin(GrailsUnitTestMixin)
    

    在你的类定义之前。

    这将在您的单元测试中注入一个名为 applicationContext 的变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多