com.google.inject.CreationException 使用 Play Framework 的 WSTestClient 进行功能测试
Posted
技术标签:
【中文标题】com.google.inject.CreationException 使用 Play Framework 的 WSTestClient 进行功能测试【英文标题】:com.google.inject.CreationException with Functional Test using Play Framework's WSTestClient 【发布时间】:2016-11-30 17:17:50 【问题描述】:我正在尝试使用 Play Framework 提供的 WsTestClient
模拟 Web 服务。
将WsTestClient
实例注入 Play 测试应用程序似乎很简单:
import javax.inject.Inject
import org.scalatest.FunSuite
import play.api.inject.guice.GuiceApplicationBuilder
import play.core.server.Server
import play.api.routing.sird._
import play.api.mvc._
import play.api.libs.json._
import play.api.test._
import play.api.inject._
import play.api.libs.ws.WSClient
import scala.concurrent.Await
class Service @Inject ()(wsClient:WSClient)
def query = wsClient.url("/service").get()
class WebServiceMockingRequestSuite extends FunSuite
test("Webservice request")
Server.withRouter()
case GET(p"/service") => Action
Results.Ok(JsNumber(42))
implicit port =>
WsTestClient.withClient client =>
val app = GuiceApplicationBuilder().bindings(bind[WSClient].to(client))
val service = app.injector.instanceOf[Service]
import concurrent.duration._
val response = Await.result(service.query,3.seconds)
assert(response.body == "42")
但在测试应用程序启动过程中,我遇到了以下异常:
[info] - Mocked webservice request *** FAILED ***
[info] com.google.inject.CreationException: Unable to create injector, see the following errors:
[info]
[info] 1) A binding to play.api.libs.ws.WSClient was already configured at playsample.webservice.tests.WebServiceMockingRequestSuite$$anonfun$1$$anonfun$apply$mcV$sp$2$$anonfun$apply$1.apply(WebServiceMockingTestSuite.scala:32):
[info] Binding(interface play.api.libs.ws.WSClient to ProviderTarget(play.api.inject.BindingKey$$anon$1@5488669d)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1).
[info] at play.api.libs.ws.ahc.AhcWSModule.bindings(AhcWS.scala:374):
[info] Binding(interface play.api.libs.ws.WSClient to ProviderConstructionTarget(class play.api.libs.ws.ahc.WSClientProvider) in interface javax.inject.Singleton) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
[info]
[info] 1 error
[info] at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:466)
[info] at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:155)
[info] at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107)
[info] at com.google.inject.Guice.createInjector(Guice.java:96)
[info] at com.google.inject.Guice.createInjector(Guice.java:84)
[info] at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:181)
[info] at playsample.webservice.tests.WebServiceMockingRequestSuite$$anonfun$1$$anonfun$apply$mcV$sp$2$$anonfun$apply$1.apply(WebServiceMockingTestSuite.scala:33)
[info] at playsample.webservice.tests.WebServiceMockingRequestSuite$$anonfun$1$$anonfun$apply$mcV$sp$2$$anonfun$apply$1.apply(WebServiceMockingTestSuite.scala:30)
[info] at play.api.test.WsTestClient$class.withClient(WSTestClient.scala:79)
[info] at play.api.test.WsTestClient$.withClient(WSTestClient.scala:87)
有趣的是,如果像这样直接注入 WSTestClient
实例,则一切正常:
test("Webservice request without service instance")
Server.withRouter()
case GET(p"/service") => Action
Results.Ok(JsNumber(42))
implicit port =>
WsTestClient.withClient client =>
val app = GuiceApplicationBuilder().bindings(bind[WSClient].to(client))
import concurrent.duration._
val response = Await.result(client.url("/service").get(),3.seconds)
assert(response.body == "42")
此测试按预期通过,没有引发com.google.inject.CreationException
异常。
【问题讨论】:
如果您只需要client
,为什么要创建整个应用程序?
这个想法是整个应用程序(使用GuiceApplicationBuilder
启动)然后可以通过Server.withRouter()
与在随机端口启动的Web 服务交互。从那以后我找到了play-mockws,它在模拟外部网络服务响应方面效果很好。
【参考方案1】:
在阅读了 Play Framework 文档中 Testing with Guice 页面的更多信息后,我能够解决该问题。
按照上面抛出的表达式 (A binding to play.api.libs.ws.WSClient was already configured
) 中给出的提示,我替换了
val app = GuiceApplicationBuilder().bindings(bind[WSClient].to(client))
与
val app = GuiceApplicationBuilder().overrides(bind[WSClient].to(client))
使测试按预期工作。
以下测试现在运行良好:
import javax.inject.Inject
import org.scalatest.FunSuite
import play.api.inject.guice.GuiceApplicationBuilder
import play.core.server.Server
import play.api.routing.sird._
import play.api.mvc._
import play.api.libs.json._
import play.api.test._
import play.api.inject._
import play.api.libs.ws.WSClient
import scala.concurrent.Await
class Service @Inject ()(wsClient:WSClient)
def query = wsClient.url("/service").get()
class WebServiceMockingRequestSuite extends FunSuite
test("Webservice request")
Server.withRouter()
case GET(p"/service") => Action
Results.Ok(JsNumber(42))
implicit port =>
WsTestClient.withClient client =>
val app = GuiceApplicationBuilder().overrides(bind[WSClient].to(client))
val service = app.injector.instanceOf[Service]
import concurrent.duration._
val response = Await.result(service.query,3.seconds)
assert(response.body == "42")
【讨论】:
以上是关于com.google.inject.CreationException 使用 Play Framework 的 WSTestClient 进行功能测试的主要内容,如果未能解决你的问题,请参考以下文章