You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Play Scala 2.6控制器实例化测试时国际化失效求助

问题原因分析

你遇到的问题核心在于:手动通过new HomeController(stubControllerComponents())创建的控制器实例,使用的是Play提供的极简测试桩组件(stub),这个组件并没有加载你的应用国际化配置和messages资源文件。

而通过inject[HomeController]或者路由调用的方式,是从Play的依赖注入容器中获取已经完整配置的控制器实例——容器里已经初始化了MessagesApi、Lang等国际化相关服务,能正确读取messages.en里的内容。

具体来说,stubControllerComponents()生成的组件默认没有配置有效的MessagesApi实现,当视图里调用messagesProvider.messages("label.welcome_to_play")时,因为没有正确的消息源,只能返回原始的键名而非解析后的文本。

解决方案:手动配置国际化相关服务

要让手动创建的控制器实例支持国际化,你需要给ControllerComponents配置正确的MessagesApi和默认语言。可以通过以下两种方式实现:

方式1:从测试应用中获取已配置的MessagesApi

既然你用了GuiceOneAppPerTest,可以直接从测试应用中获取已经初始化好的MessagesApi,然后构建自定义的ControllerComponents:

修改第一个测试的代码:

"render the index page from a new instance of controller" in {
  // 从测试应用中获取已配置的MessagesApi
  val messagesApi = inject[MessagesApi]
  // 构建包含MessagesApi的ControllerComponents
  val controllerComponents = stubControllerComponents().copy(
    messagesActionBuilder = DefaultMessagesActionBuilderImpl(
      MessagesActionImpl.parser,
      messagesApi,
      DefaultLangCookieSupportImpl(),
      stubPlayBodyParsers()
    )
  )
  
  val controller = new HomeController(controllerComponents)
  // 给FakeRequest添加默认语言(确保视图能拿到正确的Lang)
  val result = controller.index().apply(FakeRequest(GET, "/").withLang(Lang("en")))
  
  status(result) mustBe OK
  contentType(result) mustBe Some("text/html")
  contentAsString(result) must include ("Welcome to Play")
}

方式2:手动构建MessagesApi(适合更独立的测试)

如果不想依赖测试应用的DI容器,也可以手动构建MessagesApi并加载你的messages文件:

"render the index page from a new instance of controller" in {
  // 手动加载messages资源
  val messageSource = new ResourceBundleMessageSource(
    "messages", // 对应messages.en的基础文件名
    getClass.getClassLoader
  )
  val messagesApi = new DefaultMessagesApi(
    messageSource,
    Langs(Seq(Lang("en"))), // 配置支持的语言
    Lang("en") // 默认语言
  )
  
  val controllerComponents = stubControllerComponents().copy(
    messagesActionBuilder = DefaultMessagesActionBuilderImpl(
      MessagesActionImpl.parser,
      messagesApi,
      DefaultLangCookieSupportImpl(),
      stubPlayBodyParsers()
    )
  )
  
  val controller = new HomeController(controllerComponents)
  val result = controller.index().apply(FakeRequest(GET, "/").withLang(Lang("en")))
  
  status(result) mustBe OK
  contentType(result) mustBe Some("text/html")
  contentAsString(result) must include ("Welcome to Play")
}
补充说明
  • 你的视图依赖implicit MessagesProvider,而I18nSupport trait会从请求中提取Lang并结合MessagesApi生成MessagesProvider。所以给FakeRequest添加withLang(Lang("en"))能确保视图拿到正确的语言环境。
  • 重命名messages.en为messages无效,因为Play的国际化机制会根据请求的Lang自动加载对应后缀的messages文件,默认会 fallback 到无后缀的messages文件,但核心问题还是stub组件没有加载任何消息源,所以不管文件名是什么都没用。

内容的提问来源于stack exchange,提问作者consuela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:14:13