0

I'm working on a Scala Play 2.6 application that uses ReactiveMongo. I've followed the example of HomeControllerSpec.scala of the default Play 2.6 installation (play-scala-seed.g8) to test my ProjectController by creating a new instance of it but I am getting a NullPointerException.

Here's my controller:

class ProjectController @Inject()(
      cc: ControllerComponents,
      val reactiveMongoApi: ReactiveMongoApi
  )(implicit ec: ExecutionContext) extends AbstractController(cc) with I18nSupport {

  def collection: Future[JSONCollection] = reactiveMongoApi.database.map(
    _.collection[JSONCollection]("project")
  )

  def listProjects: Action[AnyContent] = Action.async { implicit request =>
    val futureProjectsList: Future[List[Project]] = collection.flatMap(
      _.find(Json.obj())
      .projection(Json.obj())
      .cursor[Project]()
      .collect[List](-1, Cursor.FailOnError[List[Project]]())
    )

    for {
      projectsList <- futureProjectsList
    } yield {
      Ok(views.html.project.list(projectsList))
    }
  }
}

And this is my test:

class ProjectControllerSpec extends PlaySpec
  with GuiceOneAppPerTest
  with Injecting
  with MockitoSugar {

  val mockedReactiveMongoApi: ReactiveMongoApi = mock[ReactiveMongoApi]
  val mockedExecutionContext: ExecutionContext = mock[ExecutionContext]

  "ProjectController GET" should {
    "render the 'List of Projects' page from a new instance of controller" in {
      val controller: ProjectController = new ProjectController(
                                                      stubControllerComponents(),
                                                      mockedReactiveMongoApi
                                                    )(mockedExecutionContext) {
        override def collection: Future[JSONCollection] = mock[Future[JSONCollection]]
      }
      val result = controller.listProjects().apply(FakeRequest(GET, "/projects"))

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

But when I run the test I get:

[info]   java.lang.NullPointerException:
[info]   at controllers.ProjectController.$anonfun$listOfProjects$1(ProjectController.scala:51)
[info]   at play.api.mvc.ActionBuilderImpl.invokeBlock(Action.scala:482)
[info]   at play.api.mvc.ActionBuilderImpl.invokeBlock(Action.scala:480)
[info]   at play.api.mvc.ActionBuilder$$anon$2.apply(Action.scala:419)
[info]   at controllers.ProjectControllerSpec.$anonfun$new$2(ProjectControllerSpec.scala:40)
[info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:20)

I also run 2 other tests for this controllers and they pass (render page from the app by injecting the controller, rendering from the router). So how can I get this test to pass? Thank you in advance for your help.

consuela
  • 1,675
  • 6
  • 21
  • 24

1 Answers1

1

The NullPointerException comes from the use of the mock objects that have no defined behavior. So when the execution reaches reactiveMongoApi.database this will cause the exception.

This github project introduced a way of mocking the reactive mongo api but it's not really maintained anymore.

You can also check acolyte that allows you to mock the mongo connection.

By the way, you should not use mocks for the ExecutionContext, otherwise your Futures won't work

vdebergue
  • 2,354
  • 16
  • 19