我正在尝试测试使用新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
而没有任何内容或标头。在我看来,FakeRequest
的内容完全被忽视了。我应该以某种方式将请求主体提供给iteratee然后运行它吗?我找不到任何例子我怎么能这样做。
答案 0 :(得分:8)
出现此问题是因为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
会返回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 */
}
答案 1 :(得分:6)
对我来说,这是:
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"}"""
}
}
}