mardi 26 avril 2016

NullPointerException thrown when unit-testing a Play controller's action that processes a form

I encounter NullPointerException when testing an action that processes a form. There are two actions, one to display and one to process the form. Testing the first one is fine; however, testing the second one throws the exception. This only happens with unit-testing; the application works fine (i.e., via browser). I can't figure out what happens. Could anyone help me shed some light on it? The code I'm testing is as follows.

  • Scala: 2.11.8
  • SBT: 0.13.11
  • Play Framework: 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")

conf/routes

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
      }
    }
  }
}

Output from running test:

[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

Aucun commentaire:

Enregistrer un commentaire