我正在开发一个play-2.4项目,并编写了一个控制器,如:
package controllers
import play.api._
import play.api.mvc._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
class Application extends Controller {
def index = Action.async { implicit request =>
Future { Ok(request.body.asJson.get) }
}
}
中有POST / controllers.Application.index
conf/routes
。
我通过执行curl --request POST --header "Content-type: application/json" --data '{"foo":"bar"}' http://localhost:9000/
检查了这项工作正常。
现在我为这个控制器写了一个规范:
package controllers
import org.specs2.mutable._
import org.specs2.runner._
import org.junit.runner._
import play.api.test._
import play.api.test.Helpers._
@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification {
"Application" should {
val controller = new Application
val fakeJson = """{ "foo":"bar" }"""
val fakeRequest = FakeRequest()
.withHeaders("Content-type" -> "application/json")
.withBody(fakeJson)
val index = controller.index()(fakeRequest).run
status(index) must equalTo(OK)
}
}
但这导致了运行时错误:
[error] None.get (Application.scala:11)
[error] controllers.Application$$anonfun$index$1$$anonfun$apply$1.apply(Application.scala:11)
[error] controllers.Application$$anonfun$index$1$$anonfun$apply$1.apply(Application.scala:11)
我在控制器中插入了println(request.body)
,发现请求正文为AnyContentAsEmpty
,意味着fakeJson
已被fakeRequest
删除。
如何正确地将JSON附加到FakeRequest?
*注意:虽然我可以写FakeRequest(POST, '/', FakeHeaders(), fakeJson)
,但我认为这不好,因为控制器规范不应该处理HTTP方法或路由。
我会感激任何帮助。
答案 0 :(得分:1)
如果客户端使用不是 JSON的请求对您的操作进行HTTP POST,request.body.asJson.get
将抛出异常。
body.asJson
返回类型为Option[JsValue]
,如果请求不是JSON,则返回None
。get
上致电None
会引发java.util.NoSuchElementException
。500 Internal Server Error
。您应该使用使用JSON body parser的操作替换def index = Action.async ...
:
import play.api.mvc.BodyParsers.parse
def index = Action.async(parse.json) ...
这实现了一些目标:
400 Bad Request
。这比500 Internal Server Error
。{/ li>造成的None.get
更合适
request.body
成为JsValue
而不是AnyContent
。因此,您只需使用request.body.asJson.get
替换request.body
即可。一般来说,你应该避免调用Option.get
,因为它不安全,并且通常有更好的方法来实现你想要的东西(在这种情况下使用适当的身体解析器恰好是更好的方法)。现在这个测试不再编译,而不是抛出由None.get
引起的异常:
val fakeJson = """{ "foo":"bar" }"""
val fakeRequest = FakeRequest()
.withHeaders("Content-type" -> "application/json")
.withBody(fakeJson)
val index = controller.index()(fakeRequest)
status(index) must equalTo(OK)
强制您将其替换为答案中的版本:
val fakeJson = play.api.libs.json.Json.parse("""{ "foo":"bar" }""")
val fakeRequest = FakeRequest().withBody(fakeJson)
val index = controller.index()(fakeRequest)
status(index) must equalTo(OK)
我的最后建议是你使用Json.obj
来清理你的测试:
val fakeJson = Json.obj("foo" -> "bar")
答案 1 :(得分:0)
<强> [SELF-解决] 强>
挣扎了几个小时,问题解决了withJsonBody
:
"Application" should {
val controller = new Application
val fakeJson = play.api.libs.json.Json.parse("""{ "foo":"bar" }""")
val fakeRequest = FakeRequest().withJsonBody(fakeJson)
val index = controller.index()(fakeRequest)
status(index) must equalTo(OK)
}
欢迎任何其他建议。