如何在 Grails 2.0 服务中对 i18n 注入 messageSource 的使用进行单元或集成测试

Posted

技术标签:

【中文标题】如何在 Grails 2.0 服务中对 i18n 注入 messageSource 的使用进行单元或集成测试【英文标题】:How to unit or integration test use of injected messageSource for i18n in Grails 2.0 service 【发布时间】:2012-02-26 10:01:00 【问题描述】:

我在 Grails 2.0 项目中的一项服务中使用消息包来处理国际化文本。用例是通过邮件插件以异步方式发送的电子邮件主题,因此将其放在控制器或 TagLib 中确实没有意义(考虑到通常的论点是不访问服务中的文本或视图)。此代码在我正在运行的 Grails 应用程序中运行良好,但我不确定如何测试它。

我在我的 defineBeans 中尝试了PluginAwareResourceBundleMessageSource,因为这是我正在运行的应用程序注入的内容,但它导致了空指针,因为它似乎需要围绕插件管理器进行大量设置,并且我的测试环境没有提供(甚至集成)。

然后我尝试了ReloadableResourceBundleMessageSource,因为它是纯 Spring,但它似乎看不到我的 .properties 文件,并且失败并在代码 'my.email.subject' 下为语言环境“en”找到没有消息.

我觉得我正在进入一个虫洞,因为 grails 文档中没有记录在服务中访问 Grails i18n,所以如果有更好的方法可以做到这一点,请告诉我。

请注意,我的 .properties 文件位于标准 grails-app/i18n 位置。

测试

@TestFor(EmailHelperService)
class EmailHelperServiceTests 

    void testSubjectsDefaultLocale() 
        defineBeans 
            //messageSource(PluginAwareResourceBundleMessageSource); Leads to nullpointers
            messageSource(ReloadableResourceBundleMessageSource);

        
        String expected = "My Expected subject Passed1 Passed2";
        String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2);
        assertEquals("email subject", expected, actual);


服务:

    class EmailHelperService 
    def messageSource;

    public String getEmailSubject(Locale locale, String param1, String param2) 
        Object[] params = [param1, param2].toArray();      
        return messageSource.getMessage("my.email.subject", params, locale );      
    

【问题讨论】:

您的意图是确保您已正确连接这一测试吗?或者您是否计划为您支持的每种语言编写一个?您的上述测试也是单元测试还是集成测试? 这个想法不是检查弹簧接线,而是更多地测试支持的各种语言,并检查 .properties 中的键和文本的正确性。为了可读性,我简化了参数,但需要测试它们的正确性。 【参考方案1】:

Grails的单元测试中已经有一个messageSource,它是一个StaticMessageSource(见http://static.springsource.org/spring/docs/2.5.4/api/org/springframework/context/support/StaticMessageSource.html),你可以通过addMessage方法添加mock消息:

messageSource.addMessage("foo.bar", request.locale, "My Message")

【讨论】:

谢谢,很高兴知道 - 是否可以使用 StaticMessageSource 和带有 0 样式占位符的消息来验证参数? 回答我自己的评论,用占位符测试,效果很好。谢谢。 我知道这个问题很老,但我发现它有助于让我走上正轨。这是我模拟消息源以进行测试的解决方案。首先,我得到了 messageSource:MessageSource messageSource = getMessageSource() messageSource 确实在单元测试中,但它是空的。所以我按照@Graem Rocher 的建议做了,并在 messageSource 中填充了该测试的相关消息。 messageSource.addMessage("messageService.sms.aNumber.recovery.message", Locale.default, "0, your A-Number is 1") 对于任何想知道它是否仍然适用的人。我已经用 Grails 3.2.5 对其进行了测试,并且效果很好。正如@Graeme 在他的回答中建议的那样,只需致电messageSource.addMessage 在 Grails 5.0.2 中不起作用。还有其他想法吗?【参考方案2】:

在单元测试和功能测试的本地方面,有时您需要 18n 目录中的真实属性。

这对我有用:

  MessageSource getI18n() 
    // assuming the test cwd is the project dir (where application.properties is)
    URL url = new File('grails-app/i18n').toURI().toURL()
    def messageSource = new ResourceBundleMessageSource()
    messageSource.bundleClassLoader = new URLClassLoader(url)
    messageSource.basename = 'messages'
    messageSource
  

  i18n.getMessage(key, params, locale)

【讨论】:

【参考方案3】:

在单元测试中,您可以通过执行以下操作来确保正确连接:

void testSubjectsDefaultLocale() 
    def messageSource = new Object()
    messageSource.metaClass.getMessage = subject, params, locale ->
        assert "my.email.subject" == subject
        assert ["Passed1", "Passed2"] == params 
        assert Locale.ENGLISH == locale
        "It Worked!!!"
    
    service.messageSource = messageSource
    String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2)
    assert "It Worked!!!" == actual

这将有助于确保您正确连接,但不能确保您所做的事情确实有效。如果您对此感到满意,那么这对您有用。如果您尝试测试,当您将“XYZ”提供给您的 .properties 文件时,它会返回“Hello”,那么这对您不起作用。

【讨论】:

感谢您的想法。我不太关心弹簧接线,但我想加载我的实际 grails .properties 文件(直接或通过 Spring),而不是在测试中声明它,因为测试内容和密钥正确性是我想要的。

以上是关于如何在 Grails 2.0 服务中对 i18n 注入 messageSource 的使用进行单元或集成测试的主要内容,如果未能解决你的问题,请参考以下文章

在 Grails 中对服务进行单元测试时如何模拟请求

将i18n消息作为参数传递给Grails模板

如何在 Grails 2.0 中运行本地插件?

服务中的 Grails 消息源错误

如何在 Grails 2.0 中创建和检索 Cookie?

如何使 MySQL 在 grails 2.0 上运行