代码之家  ›  专栏  ›  技术社区  ›  mcveat

无法使用Action.async测试控制器

  •  13
  • mcveat  · 技术社区  · 11 年前

    我正在尝试测试控制器,它正在使用新的 Action.async 下列的 documentation 我已经排除了我想测试的控制器下的部分,以分离具有类型参考的特征:

    trait UserController { this: Controller =>
      def index() = Action { /* snip */ }
      def register() = Action.async(parse.json) { request => /* snip */ }
    }
    

    文档说明我应该将其测试为:

    object UsersControllerSpec extends PlaySpecification with Results {
      class TestController() extends Controller with UserController
        "index action" should {
          "should be valid" in {
            val controller = new TestController()
            val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
            /* assertions */
          }
        }
      }
    }
    

    对于 index() 方法它工作得很好,不幸的是我不能用 register() ,因为对其应用FakeRequest会返回的实例 Iteratee[Array[Byte], SimpleResult] 。我注意到了 run() 返回的方法 Future[SimpleResult] 但无论我如何建造 FakeRequest 它返回时带有 400 没有任何内容或标题。在我看来 虚假请求 完全被忽略。我是否应该以某种方式向请求主体提供迭代,然后运行它?我找不到任何例子,我怎么能做到这一点。

    2 回复  |  直到 11 年前
        1
  •  10
  •   tjdett    10 年前

    出现这个问题是因为 play.api.mvc.Action[A] 包含以下两种应用方法:

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

    这是因为 Request[A] extends RequestHeader ,以及 A 在这种情况下,一切都不同了。如果不是正确的类型,你最终会打错电话 apply .

    当您使用 ActionBuilder 用一个 BodyParser[A] ,您创建了 Action[A] 。因此,您需要 Request[A] 测试。 parse.json 返回a BodyParser[JsValue] ,所以你需要一个 Request[JsValue] .

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

    FakeRequest() 没有给你所需要的类型。幸运的是:

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

    因此,通过在正文中使用占位符来开始编写测试:

      "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 */
      }
    
        2
  •  7
  •   Schleichardt    11 年前

    对我来说,工作是这样的:

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