Unable to test controller using Action.async

后端 未结 2 1064
长情又很酷
长情又很酷 2021-01-11 12:38

I\'m trying to test controller, which is using new Action.async. Following documentation I have excluded part under controller I want to test to separate trait

相关标签:
2条回答
  • 2021-01-11 13:03

    For me works this:

    import concurrent._
    import play.api.libs.json._
    import play.api.mvc.{SimpleResult, Results, Controller, Action}
    import play.api.test._
    import ExecutionContext.Implicits.global
    
    trait UserController {
      this: Controller =>
      def index() = Action {
        Ok("index")
      }
    
      def register() = Action.async(parse.json) {
        request =>
          future(Ok("register: " + request.body))
      }
    }
    
    object UsersControllerSpec extends PlaySpecification with Results {
    
      class TestController() extends Controller with UserController
    
      "register action" should {
        "should be valid" in {
          val controller = new TestController()
          val request = FakeRequest().withBody(Json.obj("a" -> JsString("A"), "b" -> JsString("B")))
          val result: Future[SimpleResult] = controller.register()(request)
          /* assertions */
          contentAsString(result) === """register: {"a":"A","b":"B"}"""
        }
      }
    }
    
    0 讨论(0)
  • 2021-01-11 13:19

    This problem arises because play.api.mvc.Action[A] contains these two apply methods:

    // What you're hoping for
    def apply(request: Request[A]): Future[Result]
    
    // What actually gets called
    def apply(rh: RequestHeader): Iteratee[Array[Byte], Result]
    

    This arises because Request[A] extends RequestHeader, and the A in this case makes all the difference. If it's not the right type, you'll end up calling the wrong apply.

    When you use ActionBuilder with a BodyParser[A], you create an Action[A]. As a result, you'll need a Request[A] to test. parse.json returns a BodyParser[JsValue], so you need a Request[JsValue].

    // In FakeRequest object
    def apply(): FakeRequest[AnyContentAsEmpty.type]
    

    FakeRequest() doesn't get you the type you need. Fortunately:

    // In FakeRequest class
    def withBody[B](body: B): FakeRequest[B]
    

    So, start writing your test by using a placeholder for the body:

      "should be valid" in {
        val controller = new TestController()
        val body: JsValue = ??? // Change this once your test compiles
    
        // Could do these lines together, but this shows type signatures
        val request: Request[JsValue] = FakeRequest().withBody(body)
        val result: Future[Result] = controller.index().apply(request)
    
        /* assertions */
      }
    
    0 讨论(0)
提交回复
热议问题