8

I want to test my Play application by providing mock objects during a test. Off the top of my head, there are a few ways to go about this.

  1. Provide an alternative route files during testing
  2. Use Dependency Injection, and check for a global value at runtime

I am not sure which is more feasible, or how to go about doing them. Any insight would be greatly appreciated.

Jacob Groundwater
  • 6,581
  • 1
  • 28
  • 42

4 Answers4

13

There is a third way; create your controller as a class or a trait for testing. Here is a simple example.

Your trait + implementation:

package services

trait MyService {
  def getUser(id:String):User
}

class ConcreteService extends MyService {
  override def getUser(id:String):User = {
  //Do real stuff
  }
}

In your controller class:

package controllers

import services._

class Users(service: MyService) extends Controller {
  def show(id: String) = Action {
    val user = service.getUser(id)
    Ok(views.html.user(user))
  }
}

object Users extends controllers.Users(new ConcreteService()) {}

Now you can run some unit tests..

package test

import controllers.Users
import play.api.test._
import play.api.test.Helpers._

import org.specs2.mock.Mockito
import org.specs2.mutable.Specification

class UsersSpec extends Specification with Mockito {
  val service = mock[MyService]

  "Users controller" should {
    "list users" in {
      //Insert mocking stuff here

      val users = new Users(service)
      val result = users.show("somerandomid")(FakeRequest())
      status(result) must equalTo(OK)
    }
  }
}
Blake Pettersson
  • 8,927
  • 3
  • 27
  • 36
  • Hi Blanke, thanks for the very details example. I up-voted your answer but am reluctant to mark it accepted since I think there is potential for many solutions to be listed equally. – Jacob Groundwater Apr 17 '12 at 13:40
  • 1
    Worth mentioning in this answer that the Mockito dependencies need to be added to the build.scala for it to work. As currently in 2.1 it looks like: "org.mockito" % "mockito-all" % "1.9.5" – The Trav Aug 10 '13 at 04:14
6

I had the same question, and experimented some options:

  • cake pattern
  • injection via implicit
  • spring

You can see the code on github here.

Mxyk
  • 10,678
  • 16
  • 57
  • 76
Yann Simon
  • 458
  • 3
  • 11
3

My solution is similar to Blake's, except I did it without controllers as classes. You can check out the source here.

Jason Pearson
  • 609
  • 4
  • 15
  • Author stated he didn't accept the answer because he was looking for other answers. – Jason Pearson Sep 01 '13 at 19:16
  • OK, just wanted to make sure you were aware that this question was posted 5 months ago, scratch that, asked 1 year and 5 months ago. I didn't down vote or anything, it just seemed a little odd to me. – CaptJak Sep 01 '13 at 19:24
2

For reference I have added an example of using Play's plugin framework for injecting mocked objects during testing.

  1. http://www.underflow.ca/blog/935/mock-dependency-injection-in-play-2-0

Usage of this method a mocked plugin can be provided at test time:

class Test extends Specification {
    "application" should {
        "load mock dependency" in {
            running(TestServer(9000, FakeApplication(

            // The plugin at this class replaces the default
            additionalPlugins = Seq("test.MockInjector")

            )), HTMLUNIT) { browser =>
                browser.goTo("http://localhost:9000")

                // Test mock controller

            }
        }
    }
}

The MockInjector can be used to provide controller objects, or any other injectable component.

Note: I wrote the blog entry, and anyone is free to migrate any and all content from the blog to here.

Jacob Groundwater
  • 6,581
  • 1
  • 28
  • 42