scala - 如何测试使用 WsClient 自己发出请求的 Play 应用程序?
问题描述
我有一个 Play 2.7.x 应用程序,它应该将请求转发到不同的 URL。它有一个控制器,实现如下:
import play.api.mvc._
import play.api.libs.ws.WSClient
class MyController(val controllerComponents: ControllerComponents, ws: WSClient, baseUrl: String) extends BaseController {
// POST /foo routed here
def foo() = {
Action.async { request =>
ws.url(s"http://$baseUrl/foo").post(equest.body.asJson.get).map(_ -> Ok(""))
}
}
}
我现在想创建一个发出假请求的测试,并使用假服务器来测试所有内容。在https://www.playframework.com/documentation/2.7.x/ScalaTestingWebServiceClients之后,我尝试了以下操作:
class ControllersSpec extends PlaySpec with OneAppPerSuiteWithComponents {
override lazy val components = new BuiltInComponentsFromContext(context) with NoHttpFiltersComponents with AhcWSComponents {
lazy val myController = new MyController(controllerComponents, wsClient, "localhost:19001")
lazy val router = new Routes(httpErrorHandler, myController)
}
"My Controller" should {
"forward requests" in {
Server.withRouterFromComponents(ServerConfig(port=Some(19001))) {
import play.api.routing.sird._
routes: BuiltInComponents => {
case POST(p"/foo") =>
routes.defaultActionBuilder {
Ok("")
}
}
} { port =>
route(app, FakeRequest(POST, "/foo", FakeHeaders(), "{\"foo\": \"bar\"}") // <-- line 86
}
}
}
}
但是,尝试运行它会导致:
java.lang.IllegalStateException: cannot create children while terminating or terminated
at akka.actor.dungeon.Children$class.makeChild(Children.scala:270)
at akka.actor.dungeon.Children$class.attachChild(Children.scala:48)
at akka.actor.ActorCell.attachChild(ActorCell.scala:370)
at akka.stream.impl.ExtendedActorMaterializer.actorOf(ActorMaterializerImpl.scala:60)
at akka.stream.impl.GraphStageIsland.onIslandReady(PhasedFusingActorMaterializer.scala:742)
at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:507)
at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:420)
at akka.stream.impl.PhasedFusingActorMaterializer.materialize(PhasedFusingActorMaterializer.scala:415)
at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:496)
at akka.stream.scaladsl.Source.runWith(Source.scala:83)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:203)
at play.api.test.EssentialActionCaller$class.call(Helpers.scala:249)
at play.api.test.Helpers$.call(Helpers.scala:601)
at play.api.test.RouteInvokers$class.route(Helpers.scala:271)
at play.api.test.Helpers$.route(Helpers.scala:601)
at play.api.test.RouteInvokers$class.route(Helpers.scala:281)
at play.api.test.Helpers$.route(Helpers.scala:601)
at controllers.ControllersSpec$$anonfun$1$$anonfun$apply$mcV$sp$2$$anonfun$3.apply(ControllersSpec.scala:86)
我假设测试服务器和应用程序对 Akka 的使用受到干扰,并且其中一个过早地终止了另一个,但我不知道它们的工作原理足以完全理解它。我将如何正确设置这样的测试?
解决方案
如果您不介意使用外部库,我建议其中两个:
这可能是您想要的,设置它您只需要:
val mockWs = MockWS {
case ("POST", "/foo") => Action { Ok(Json.parse("{\"foo\": \"bar\"}")) }
}
override lazy val app: Application = new GuiceApplicationBuilder()
//and override guice WSClient instance with MockWS
.overrides(bind[WSClient].toInstance(mockWs))
.build()
西莫克:
Siremock 是一个 Wiremock 包装器。设置起来比较困难,但是,除了模拟之外,它还有许多其他功能,例如,验证您的请求是否真的发出:
val request =
(on(urlEqualTo("/foo")))
.withHttpMethod(HttpMethods.POST)
.withContentType("application/json")
request respond (aResponse withBody "{\"foo\": \"bar\"}")
//execute your test here
verify(request) wasCalled exactly(1)
[]的
推荐阅读
- vue.js - Vue.js - 如何在滚动时更改图像 src?
- c# - 如何更正用于创建 Canvas 的过时代码
- node.js - 如何使用 node.js 将 JSON 文件加载到谷歌 Bigquery
- reactjs - 错误:分页(...):渲染没有返回任何内容。这通常意味着缺少 return 语句。或者,不渲染任何内容,返回 null
- .net - Azure B2C .. 无法授予管理员同意。您的组织没有以下 API 的订阅(或服务主体)
- laravel - 为什么当从数字搜索以 0 开始时 Laravel 控制器不显示零前导
- javascript - 这是传播运算符的有效用法吗
- jdbc - 如何使用 Google Cloud 上的 Ingress 公开 CockroachDB 以进行外部负载测试
- jquery - 如何延迟 onClick 图像链接,以便 .gif 动画可以在页面切换之前完成?
- rust - &() 语法的目的是什么?