无法使用scalamock模拟WSRequest.post()
我正在使用Scalamock和Scalatest为Play应用程序编写单元测试 我的原始代码如下所示:无法使用scalamock模拟WSRequest.post(),scala,playframework,scalamock,play-ws,Scala,Playframework,Scalamock,Play Ws,我正在使用Scalamock和Scalatest为Play应用程序编写单元测试 我的原始代码如下所示: // Here ws is an injected WSClient val req = Json.toJson(someRequestObject) val resp: Future[WSResponse] = ws.url(remoteURL).post(Json.toJson(req)) 在一部分中,我必须模拟对web服务的外部调用,我正试图使用scalamock来实现这一点: ws
// Here ws is an injected WSClient
val req = Json.toJson(someRequestObject)
val resp: Future[WSResponse] = ws.url(remoteURL).post(Json.toJson(req))
在一部分中,我必须模拟对web服务的外部调用,我正试图使用scalamock来实现这一点:
ws = stub[WSClient]
wsReq = stub[WSRequest]
wsResp = stub[WSResponse]
ws.url _ when(*) returns wsReq
wsReq.withRequestTimeout _ when(*) returns wsReq
(wsReq.post (_: java.io.File)).when(*) returns Future(wsResp)
我能够成功地使用文件模拟post请求,但无法使用JSON模拟post请求
我尝试分别放置存根函数引用,如:
val f: StubFunction1[java.io.File, Future[WSResponse]] = wsReq.post (_: java.io.File)
val j: StubFunction1[JsValue, Future[WSResponse]] = wsReq.post(_: JsValue)
我得到第二行的编译错误:无法解析重载的方法post
我错过了什么?为什么我不能模拟一个重载方法,而不能模拟另一个方法?
play.api.libs.ws.WSRequest
有两个post
方法(),分别是:
文件
T
(其中T
对可写的有一个隐式边界)
post
。但是,JsValue
不能替换为文件
实际上,您希望调用第二个版本,但这是一个采用两组参数的curried方法(尽管第二个是隐式的)。因此,您需要显式地提供您期望隐式的模拟值,即
val j:StubFunction1[JsValue,Future[WSResponse]]=wsReq.post(quo:JsValue)(隐式[Writeable[JsValue]])
因此,一个有效的解决办法是:
(wsReq.post()())。当(*)返回Future(wsResp)
旧答案:
WSRequest
提供了post
方法()的4个重载,其中包括:
String
JsonNode
InputStream
文件
您可以使用
文件进行模拟,因为它匹配重载4,但JsValue
不匹配(这是Play JSON模型的一部分,而JsonNode
是Jackson JSON模型的一部分)。如果您转换为字符串
或JsonNode
,那么它将解决正确的重载并进行编译。我的最佳猜测是,您的WSRequest
实际上是一个play.libs.ws.WSRequest
,它是Java API的一部分,而您应该使用play.API.libs.ws.WSRequest
,它是Scala API
该方法存在并由Scala API中的WSBodyWritables
隐式提供,但不在Java API中
另一个原因可能是您的JsValue
不是一个play.api.libs.json.JsValue
,而是其他东西(例如spray.json.JsValue
)。我将引用一个成功实现您尝试的示例,主要区别是我使用了mock
而不是stub
重要的部分是:
val ws = mock[WSClient]
val responseBody = "{...}"
...
"availableBooks" should {
"retrieve available books" in {
val expectedBooks = "BTC_DASH ETH_DASH USDT_LTC BNB_LTC".split(" ").map(Book.fromString).map(_.get).toList
val request = mock[WSRequest]
val response = mock[WSResponse]
val json = Json.parse(responseBody)
when(ws.url(anyString)).thenReturn(request)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.get()).thenReturn(Future.successful(response))
whenReady(service.availableBooks()) { books =>
books.size mustEqual expectedBooks.size
books.sortBy(_.string) mustEqual expectedBooks.sortBy(_.string)
}
}
}
您可以在以下位置看到完整的测试:我想如果您模拟一个JsValue响应,它应该可以正常工作
when(wsReq.post(Json.parse("""{...json request...}"""))).thenReturn(Future(wsResp))
这里Json.parse
返回JsValue
。您应该在请求正文中传递您期望的json字符串。谢谢Woodz。这个问题对于Scala来说非常特殊。它没有用于JsonNode的重载方法。这里假定的过度使用是:def post[T](body:T)(隐式arg0:bodywriteable[T]):Future[Response]
Thank@Xolve-我没有注意到您使用的是Scala Play ApiThank@J0HN。你的回答为我提供了我所需要的:)尽管实际的解决方案与应该的有点不同。1.需要显式类型。2.需要两个通配符参数。它看起来像:(wsReq.post(:JsValue)(:bodywriteable[JsValue])当(*,*)返回Future(wsResp)
时,您是如何得出包含隐式表达式的结论的?在post方法的声明中,没有这样的东西:override def post[T:bodywriteable](body:T):Future[Response]
@Xolve Scala中的上下文绑定是泛型类型上专用的该类型的隐式参数的语法糖。例如,post[T:BodyWriteable]
与post[T](隐式证据$0:BodyWriteable[T])
()相同,您尝试过吗?