FAQ

[play-framework] Controller Test with FakeRequest withFormUrlEncodedBody fails

Ant Kutschera
Mar 19, 2013 at 9:09 pm
I posted a bug at:https://github.com/playframework/Play20/issues/857

The bug was closed. Point #2 says:

"*You are invoking the action directly. The action returns an iteratee, and
this iteratee must be fed the body, but you are feeding nothing into it,
because you call the **run method on it. This is why the body is not
passed. Instead, use play.api.test.Helpers.route, this will feed the body
you supplied to withFormUrlEncodedBody** into the iteratee for you.*"

In the bug report, I clearly stated that I need to test the action
directly, because I want to stub/mock dependencies which the controller has.

Could I do the stubbing/mocking AND use the Helpers.route function? I was
hoping to write a unit test, but this is much more of an integration test...

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
reply

Search Discussions

6 responses

  • Ant Kutschera at Mar 19, 2013 at 9:17 pm
    PS The code doesn't use a dependency injection framework which I could
    configure to inject stubbed dependencies.

    Code is
    here: https://github.com/maxant/share/blob/master/playframework_Play20_issues_857.zip?raw=true

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Ant Kutschera at Mar 19, 2013 at 9:23 pm
    PPS, how is specs so different to JUnit, that it requires a different setup?

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Ant Kutschera at Mar 19, 2013 at 10:03 pm
    PPPS Both http://www.playframework.com/documentation/2.1.0/ScalaTest
    and http://www.playframework.com/documentation/2.1.0/ScalaFunctionalTest
    show how to test controllers directly and do not mention anything about
    having to use the route function. Is this a requirement because my
    controller method works with Async and parallel code, or is this a bug in
    Play which needs fixing? The documentation at least needs an update to
    clarify this.

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • James Roper at Mar 20, 2013 at 4:43 am

    On Wednesday, March 20, 2013 9:03:12 AM UTC+11, Ant Kutschera wrote:

    PPPS Both http://www.playframework.com/documentation/2.1.0/ScalaTest and
    http://www.playframework.com/documentation/2.1.0/ScalaFunctionalTest show
    how to test controllers directly and do not mention anything about having
    to use the route function. Is this a requirement because my controller
    method works with Async and parallel code, or is this a bug in Play which
    needs fixing? The documentation at least needs an update to clarify this.
    Yes, the documentation does need to be updated to clarify this, the
    information about unit testing controllers like that is just wrong.

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • James Roper at Mar 20, 2013 at 4:39 am

    On Wednesday, March 20, 2013 8:09:09 AM UTC+11, Ant Kutschera wrote:

    I posted a bug at:https://github.com/playframework/Play20/issues/857

    The bug was closed. Point #2 says:

    "*You are invoking the action directly. The action returns an iteratee,
    and this iteratee must be fed the body, but you are feeding nothing into
    it, because you call the **run method on it. This is why the body is not
    passed. Instead, use play.api.test.Helpers.route, this will feed the body
    you supplied to withFormUrlEncodedBody** into the iteratee for you.*"

    In the bug report, I clearly stated that I need to test the action
    directly, because I want to stub/mock dependencies which the controller has.

    Could I do the stubbing/mocking AND use the Helpers.route function? I was
    hoping to write a unit test, but this is much more of an integration test...
    If you have a look at the signature of your action, it is this:

    RequestHeader => Iteratee[Array[Byte], Result]

    RequestHeader has no body. So although FakeRequest, which extends
    RequestHeader, does have a body, your action will ignore it, since it only
    sees RequestHeader. The body on FakeRequest is taken by Helpers.route,
    serialised into a byte array, and then fed into the returned Iteratee,
    which is the body parser for your action. That's how Helpers.route passes
    the body to your action. Since you're just invoking Iteratee.run, which
    means you are feeding nothing into the action, your action is getting no
    body. So, one option would be for you to serialise the body you want and
    feed it into the iteratee.

    Yes, you can use stubbing/mocking and use the Helpers.route function.
    FakeApplication accepts a Global, you can create a mock Global that
    implements getControllerInstance, and inject stubs there.

    Another option would be for us to provide a Helpers.call(EssentialAction,
    FakeRequest) method that did this. Have to think a bit more about that.

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Ant Kutschera at Mar 20, 2013 at 7:34 pm
    Hi James,

    Thanks for the quick feedback.

    It turns out that I don't need to use a global in the fake app, since I can
    just setup the stubs in the controller objects before calling "route". Not
    sure why I didn't grasp that earlier, it's obvious really :-)

    Is the recommendation then to never call a controller method directly, or
    only in cases where AsyncResults are returned? If you could get the docs
    updated, that would be super.


    Another option would be for us to provide a Helpers.call(EssentialAction,
    FakeRequest) method that did this. Have to think a bit more about that.
    I guess it might be nice to be able to test the controller without the
    routes, e.g. I wouldn't have to set the URL in the fake request to some
    ugly string which causes a dependency between the routes file and my tests.
    But I can live with the given solution.

    Thanks,
    Ant

    PS The test now looks like this and runs successfully:

    class ValidationControllerTest extends play.test.WithApplication {

    @Test
    def testValidate {

    import scala.collection.JavaConversions._

    val fakeApp = new play.test.FakeApplication(
    new java.io.File("."),
    classOf[FakeApplication].getClassLoader,
    new java.util.HashMap,

    List("ch.maxant.scalabook.play20.plugins.xasupport.XASupportPlugin"),
    null)

    start(fakeApp)

    //setup inputs
    val request = FakeRequest(POST, "/validate").
    withSession(ValidationController.EventUid -> "LKJSC-W1").
    withSession(Secured.Username -> "lana@hippodrome-london.com").
    withHeaders("content-type" ->
    "application/x-www-form-urlencoded").
    withFormUrlEncodedBody(ValidationController.BookingRef ->
    "bookingRefAsdf")

    //setup dependencies
    ValidationController.ticketGateway = TicketGatewayStub
    ValidationController.validationRepository = ValidationRepoStub
    ValidationController.userRepository = UserRepoStub

    //call to method under test
    val result = route(request).get

    //assertions
    val c = contentAsString(result) //waits for async result
    val s = status(result)
    assertEquals(OK, s)
    assertTrue(c.contains("bookingRefStillOpen"))
    assertFalse(c.contains("bookingRefAsdf"))
    }

    --
    You received this message because you are subscribed to the Google Groups "play-framework" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post

2 users in discussion

Ant Kutschera: 5 posts James Roper: 2 posts