【问题标题】:NullPointerException thrown when unit-testing a Play controller's action that processes a form对处理表单的 Play 控制器操作进行单元测试时抛出 NullPointerException
【发布时间】:2017-04-01 05:37:55
【问题描述】:

我在测试处理表单的操作时遇到NullPointerException。有两种操作,一种用于显示,一种用于处理表单。测试第一个很好;但是,测试第二个会引发异常。这只发生在单元测试中;该应用程序运行良好(即通过浏览器)。我不知道会发生什么。谁能帮我解释一下?我正在测试的代码如下。

  • 斯卡拉:2.11.8
  • SBT:0.13.11
  • 播放框架:2.5.2

build.sbt

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  "org.mockito" % "mockito-core" % "1.10.19" % Test,
  "org.scalatestplus.play" %% "scalatestplus-play" % "1.5.1" % Test
)

project/plugins.sbt

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.2")

配置/路由

GET     /           controllers.FormController.showForm
POST    /           controllers.FormController.processForm

app/controllers/FormController.scala

package controllers

import javax.inject.Inject

import play.api.data.Form
import play.api.data.Forms._
import play.api.i18n.{I18nSupport, MessagesApi}
import play.api.mvc._

case class UserData(name: String, email: String)

class FormController @Inject()(val messagesApi: MessagesApi) extends
  Controller with
  I18nSupport {

  def showForm = Action {
    Ok(views.html.showForm(getForm))
  }

  def processForm = Action { implicit request =>
    getForm.bindFromRequest.fold(
      errForm => Ok(views.html.showForm(errForm)),
      userData => Ok(userData.toString)
    )
  }

  val getForm: Form[UserData] = Form(mapping(
    "name" -> nonEmptyText,
    "email" -> email
  )(UserData.apply)(UserData.unapply))
}

views/main.scala.html

@(content: Html)

<!DOCTYPE html>
<html lang="en">
<body>
  @content
</body>
</html>

views/showForm.scala.html

@import helper._

@(myForm: Form[UserData])(implicit messages: Messages)

@main {
  <h3>Form</h3>
  @form(action = routes.FormController.processForm()) {
    @inputText(myForm("name"))
    @inputText(myForm("email"))
    <input type="submit" value="Submit">
  }
}

test/controllers/FormControllerSpec.scala

package controllers

import org.scalatest.mock.MockitoSugar
import org.scalatestplus.play.PlaySpec
import play.api.i18n.MessagesApi
import play.api.test.Helpers._
import play.api.test._

class FormControllerSpec extends PlaySpec with MockitoSugar {
  "FormController" when {
    "showForm" should {
      "display the form" in {
        val cut = new FormController(mock[MessagesApi])
        val response = cut.showForm(FakeRequest())
        status(response) mustBe OK
      }
    }

    "processForm" should {
      "redisplay the form in case of form errors" in {
        val cut = new FormController(mock[MessagesApi])
        val req = FakeRequest(POST, routes.FormController.processForm.path)
        val response = cut.processForm(req)
        status(response) mustBe OK
      }
    }
  }
}

运行测试的输出:

[info] FormControllerSpec:
[info] FormController
[info]   when showForm
[info]   - should display the form
[info]   when processForm
[info]   - should redisplay the form in case of form errors *** FAILED ***
[info]     java.lang.NullPointerException:
[info]     at views.html.helper.FieldElements$$anonfun$errors$2$$anonfun$apply$5.apply(Helpers.scala:35)
[info]     at views.html.helper.FieldElements$$anonfun$errors$2$$anonfun$apply$5.apply(Helpers.scala:35)
[info]     at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info]     at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info]     at scala.collection.immutable.List.foreach(List.scala:381)
[info]     at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[info]     at scala.collection.immutable.List.map(List.scala:285)
[info]     at views.html.helper.FieldElements$$anonfun$errors$2.apply(Helpers.scala:35)
[info]     at views.html.helper.FieldElements$$anonfun$errors$2.apply(Helpers.scala:31)
[info]     at scala.Option.getOrElse(Option.scala:121)
[info]     ...
[info] ScalaTest

【问题讨论】:

  • 您的发帖请求很可能无效

标签: scala unit-testing playframework-2.5


【解决方案1】:

在您发布的示例中,您尚未训练您的模拟。因此,当您尝试渲染模板时,它会尝试在模拟上调用 apply 并且它会抛出。供参考,MessagesApi:

https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/i18n/Messages.scala#L320

正确训练这个模拟是非常困难的。相反,您可以做的是构建DefaultMessagesApi 的实例并将其连接到您的控制器:

val config = Configuration(ConfigFactory.load("application.conf")) // Or test.conf, if you have test-specific config files
val messages = new DefaultMessagesApi(Environment.simple(), config, new DefaultLangs(config))
val controller = wire[MyController]

【讨论】:

    猜你喜欢
    • 2017-12-11
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多