Play Framework with Internationalization 测试失败

Play Framework with Internationalization test fails

当我 运行 我的 Play Scala 2.6 应用程序启用了国际化时,页面呈现时所有内容都从我的 messages.en 文件中正确拾取。

但是当我测试我的控制器时,其中一项测试在检查页面内容时失败了 (contentAsString(result) must include ("Welcome to Play"))。

测试失败,因为页面内容呈现为 label.welcome_to_play 而不是 Welcome to Play!。只有当我从控制器的新实例呈现索引页面时才会发生这种情况。当我通过从应用程序或路由器渲染页面进行测试时,相同的测试 (contentAsString) 正在通过。

你知道为什么会这样吗?

这是我的 HomeController.scala:

@Singleton
class HomeController @Inject()(cc: ControllerComponents)
  extends AbstractController(cc) with I18nSupport {

  def index() = Action { implicit request: Request[AnyContent] =>
    Ok(views.html.index())
  }
}

这是我的 HomeControllerSpec.scala 测试:

class HomeControllerSpec extends PlaySpec
  with GuiceOneAppPerTest
  with Injecting
  with Results {

  "Calling HomeController.index" should {

    "render the index page from a new instance of controller" in {
      val controller = new HomeController(stubControllerComponents())
      val result = controller.index().apply(FakeRequest(GET, "/"))

      status(result) mustBe OK
      contentType(result) mustBe Some("text/html")
      // THIS IS WHERE THE TEST FAILS. Content appears as "label.welcome_to_play"
      contentAsString(result) must include ("Welcome to Play")
    }

    "render the index page from the application" in {
      val controller = inject[HomeController]
      val home = controller.index().apply(FakeRequest(GET, "/"))

      status(home) mustBe OK
      contentType(home) mustBe Some("text/html")
      // WHILE THIS IS PASSING
      contentAsString(home) must include ("Welcome to Play")
    }

    "render the index page from the router" in {
      val request = FakeRequest(GET, "/")
      val home = route(app, request).get

      status(home) mustBe OK
      contentType(home) mustBe Some("text/html")
      // AND THIS IS PASSING
      contentAsString(home) must include ("Welcome to Play")
    }
  }
}

这是我的 index.scala.html 观点:

@()(implicit messagesProvider: MessagesProvider)

@main(messagesProvider.messages("label.welcome_to_play")) {
  <h1>@messagesProvider.messages("label.welcome_to_play")</h1>
}

这是我的 messages.en 文件的样子:

label.welcome_to_play = Welcome to Play!

我的 conf 文件中有以下配置:

play.i18n {
  langs = [ "en" , "lv ]
}

我尝试将文件从 messages.en 重命名为 messages 但它没有帮助。

有谁知道为什么测试失败?为什么在从我的控制器的新实例呈现页面时不使用消息文件?预先感谢您的帮助:)

MessagesApiControllerComponents 提供,将包含消息列表及其翻译。

当你在其中使用stubControllerComponents这个will create a MessagesApi object with no messages

如果您想要翻译的消息,您需要使用其他 ControllerComponents

我最终用 testMessages 映射实例化了 DefaultMessagesApi,如下所示:

首先,我在 HomeControllerSpec 中创建了一个 testMessages 地图:

private val testMessages: Map[String, Map[String, String]] = Map(
  "en" -> Map(
    "label.welcome_to_play" -> "Welcome to Play!",
    "label.hello_world" -> "Hello world"
  )
)

此地图仅包含我要测试的一小部分标签,并非完整 messages.en 文件的副本。

然后在失败的测试中,我通过覆盖 messagesApi...

创建了 HomeController 的新实例
"render the index page from a new instance of controller" in {
  val controller = new HomeController(stubControllerComponents()) {
    override val messagesApi = new DefaultMessagesApi(testMessages)
  }
  val result: Future[Result] = controller.index().apply(FakeRequest(GET, "/"))

  status(result) mustBe OK
  contentType(result) mustBe Some("text/html")
  contentAsString(result) must include ("Welcome to Play")
}

...测试通过。

我承认这种方法会导致一些重复(messages.en 文件和规范中的消息标签)但是对于没有太多消息要测试的小型测试,我认为这是一个可以接受的解决方案。