我正在编写一个新的Scala Play 2.6 Web服务,并尝试为接受XML有效负载的控制器编写单元测试。但是,当我从单元测试中调用控制器时,我从主体解析器返回400(代码根本没有进入控制器方法体),错误消息显示为For request 'PUT /series/97234752' [Invalid XML: Premature end of file.]
。正在解析的XML是有效的,我甚至通过加载一个非常简单的XML字符串来测试它,导致相同的错误。我已经读过这个问题可能与bodysarser尝试从已经读过的流中读取有关,但我无法弄清楚如何正确地执行它(如果这是问题)。
这是单元测试代码:
@RunWith(classOf[JUnitRunner])
class SeriesControllerSpec(implicit ee: ExecutionEnv) extends PlaySpecification with Mockito {
val coreApi = mock[CoreApiService]
val app = new GuiceApplicationBuilder().overrides(bind[CoreApiService].toInstance(coreApi)).build
"SeriesController#save" should {
"save a valid series in core-api and return the full model upon success" in new WithApplication(app) {
val body = XML.load(getClass.getResource("/SeriesControllerSpec/valid_series.xml"))
val coreApiResponse = Series(
epgContentSourceId = "",
seriesId = Some("54321"),
partnerSeriesId = "97234752",
seriesTexts = Set(
LocalizedTextField(content = "English Title", field = "title", `type` = "full", lang = "en"),
LocalizedTextField(content = "Brief English Title", field = "title", `type` = "brief", lang = "en"),
LocalizedTextField(content = "English Sort Title", field = "title", `type` = "sort", lang = "en"),
LocalizedTextField(content = "English Description", field = "description", `type` = "full", lang = "en"),
LocalizedTextField(content = "Brief English Description", field = "description", `type` = "brief", lang = "en"),
LocalizedTextField(content = "Spanish Title", field = "title", `type` = "full", lang = "es"),
LocalizedTextField(content = "Brief Spanish Title", field = "title", `type` = "brief", lang = "es"),
LocalizedTextField(content = "Spanish Sort Title", field = "title", `type` = "sort", lang = "es"),
LocalizedTextField(content = "Spanish Description", field = "description", `type` = "full", lang = "es"),
LocalizedTextField(content = "Brief Spanish Description", field = "description", `type` = "brief", lang = "es")
),
genres = Set(Genre(genre = "documentary", `type` = Some("nielsen"))),
categories = Set(Category(name = "original", `type` = None), Category(name = "Europe > UK > Manchester", `type` = Some("location"))).toSet
)
coreApi.saveSeries(any[Series]) returns Future(coreApiResponse, true)
val controller = app.injector.instanceOf[SeriesController]
val result = controller.save("97234752")(FakeRequest(method = "PUT", path = "/series/97234752").withHeaders(("Content-Type", "application/xml")).withXmlBody(body))
val res = Await.result(result.run(), 1 second)
res must be_===(Created(""))
}
}
}
这是控制器的(部分):
class SeriesController @Inject()(coreApi: CoreApiService)(implicit val executionContext: ExecutionContext) extends XmlController {
def save(seriesId: String) = Action.async(parse.xml) { request =>
// execution never reaches in here
}
}
答案 0 :(得分:1)
问题是您在控制器中使用parse.body
。当您打算使用PlayBodyParsers中的一个解析器时,如parse.xml
;你必须使用方法play.api.test.Helpers.call
来获得结果。以下是实施的示例:
控制器:
package controllers
import javax.inject.{Inject, Singleton}
import play.api.mvc._
import scala.xml.NodeSeq
@Singleton
class XmlController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
private final val requestMaxLength: Int = 99999
def post: Action[NodeSeq] = Action(parse.xml(requestMaxLength)) { implicit request: Request[NodeSeq] =>
Ok(request.body)
}
}
测试:
package controllers
import akka.stream.Materializer
import org.scalatest.{FlatSpec, Matchers, OptionValues}
import org.scalatestplus.play.guice._
import play.api.http.{HeaderNames, MimeTypes}
import play.api.mvc.{AnyContentAsXml, ControllerComponents, Request, Result}
import play.api.test.Helpers._
import play.api.test._
import scala.concurrent.Future
import scala.io.Source
import scala.xml.NodeSeq
class XmlControllerTest extends FlatSpec with Matchers with GuiceOneAppPerTest with OptionValues with Injecting with HeaderNames {
lazy val cc: ControllerComponents = inject[ControllerComponents]
lazy implicit val materializer: Materializer = app.materializer
"Post" should "create a valid xml" in {
val xmlString: String = Source.fromResource("request.xml").getLines().mkString
val xml: NodeSeq = scala.xml.XML.loadString(xmlString)
val controller: XmlController = new XmlController(cc)
val request: Request[AnyContentAsXml] = FakeRequest()
.withMethod(POST)
.withHeaders(CONTENT_TYPE -> MimeTypes.XML)
.withXmlBody(xml)
val postResult: Future[Result] = call(controller.post, request)
play.api.test.Helpers.call()
status(postResult) should equal(OK)
contentType(postResult).value should equal(MimeTypes.XML)
}
}
重要的一点是:
val postResult:Future [Result] = call(controller.post,request)
我希望这可以解决您的问题。