在play scala的单元测试中模拟WsClient
Mocking WsClient in unit tests in play scala
考虑以下片段;我在这里使用 WSClient 通过 DI 进行一些 api 调用。
@Singleton
class SampleService @Inject()(ws: WSClient) {
def get(id:Long): JsValue ={
val trailingURL = s"/$id".toString
val wsRequest = ws.url(baseURL+trailingURL).addQueryStringParameters("access_token" -> authToken).get()
val wsResponse = Await.result(wsRequest, Duration.Inf)
Json.toJson(wsResponse.body)
}
}
而且我需要为 get 方法编写单元测试。我正在做以下事情
val mockedWS = mock[WSClient]
val sparrowService = new SurveySparrowService(mockedWS)
"get method" should {
"return a valid result with valid id" in {
val result = sparrowService.get(66405)
println(result)
assert(result.toString == `the result i'll get`)
}
}
但是模拟失败了,我在下一行得到了一个空指针异常=>
val wsRequest = ws.url(baseURL+trailingURL).addQueryStringParameters("access_token" -> authToken).get()
此外,当我使用 Json.toJson(wsResponse.body) 时,整个响应中的每个参数都会得到额外的 \。
谁能帮我解决这两个问题。谢谢
存在 play-mockws,它存在的唯一原因是手动模拟 WSClient 非常乏味。
// simulation of a GET request to http://dns/url
val ws = MockWS {
case (GET, "http://dns/url") => Action { Ok("http response") }
}
await(ws.url("http://dns/url").get()).body == "http response"
进一步说明:
模拟一个 class / trait 只是凭空为你创建一个该类型的实例。一般来说,你不能对该实例做任何事情,调用它的任何方法只会 return null
。如果您的测试代码调用此对象的方法,您必须用答案存根这些方法(即简单地 return 一个准备好的值)。
对于 WSClient
,这意味着您必须存根 url
方法,因为任何执行 HTTP 请求的代码都会调用该方法。但是这个方法return是WSRequest
。所以,你也必须模拟这个……对这个新模拟的任何调用也需要被存根,否则它将再次以 NPE 结束。这很快就会变得很复杂,您可能不再太了解您的测试代码。这就是创建 play-mockws 的原因,这使得在您的 Play 应用程序中推断对 HTTP 服务的调用变得非常容易。
顺便说一句,您还可以将 play-mockws 与 SIRD - String Interpolation Router DSL 结合使用,这使得在需要时更容易从路由或查询参数中提取值:
val ws = MockWS {
case GET(p"/$id") if id == "66405" =>
Action {
Results.Ok("...")
}
}
考虑以下片段;我在这里使用 WSClient 通过 DI 进行一些 api 调用。
@Singleton
class SampleService @Inject()(ws: WSClient) {
def get(id:Long): JsValue ={
val trailingURL = s"/$id".toString
val wsRequest = ws.url(baseURL+trailingURL).addQueryStringParameters("access_token" -> authToken).get()
val wsResponse = Await.result(wsRequest, Duration.Inf)
Json.toJson(wsResponse.body)
}
}
而且我需要为 get 方法编写单元测试。我正在做以下事情
val mockedWS = mock[WSClient]
val sparrowService = new SurveySparrowService(mockedWS)
"get method" should {
"return a valid result with valid id" in {
val result = sparrowService.get(66405)
println(result)
assert(result.toString == `the result i'll get`)
}
}
但是模拟失败了,我在下一行得到了一个空指针异常=>
val wsRequest = ws.url(baseURL+trailingURL).addQueryStringParameters("access_token" -> authToken).get()
此外,当我使用 Json.toJson(wsResponse.body) 时,整个响应中的每个参数都会得到额外的 \。 谁能帮我解决这两个问题。谢谢
存在 play-mockws,它存在的唯一原因是手动模拟 WSClient 非常乏味。
// simulation of a GET request to http://dns/url
val ws = MockWS {
case (GET, "http://dns/url") => Action { Ok("http response") }
}
await(ws.url("http://dns/url").get()).body == "http response"
进一步说明:
模拟一个 class / trait 只是凭空为你创建一个该类型的实例。一般来说,你不能对该实例做任何事情,调用它的任何方法只会 return null
。如果您的测试代码调用此对象的方法,您必须用答案存根这些方法(即简单地 return 一个准备好的值)。
对于 WSClient
,这意味着您必须存根 url
方法,因为任何执行 HTTP 请求的代码都会调用该方法。但是这个方法return是WSRequest
。所以,你也必须模拟这个……对这个新模拟的任何调用也需要被存根,否则它将再次以 NPE 结束。这很快就会变得很复杂,您可能不再太了解您的测试代码。这就是创建 play-mockws 的原因,这使得在您的 Play 应用程序中推断对 HTTP 服务的调用变得非常容易。
顺便说一句,您还可以将 play-mockws 与 SIRD - String Interpolation Router DSL 结合使用,这使得在需要时更容易从路由或查询参数中提取值:
val ws = MockWS {
case GET(p"/$id") if id == "66405" =>
Action {
Results.Ok("...")
}
}