我有一个函数可以对外部 API 进行 API 调用
假设该函数执行如下简单操作。仅供参考,需要导入
scala.io.Source
def myFunction(apiRequestUrl: String) : MyObject = {
val response: String = Source.fromURL(apiRequestUrl).mkString
val formatedResponse: MyObject = formatResponseFunction(response)
formatedResponse
}
我知道我可能收到的一些错误代码是 400、404 等...并且我想一般地处理由此产生的任何错误代码。这怎么可能做到呢?我发现的例子似乎是在测试一个人自己构建的 REST API,而不是对其他人外部 API 的函数调用
为了模拟外部服务调用,您可以使用 Mockito,这是一个模拟框架。 Mockito 使用起来非常简单,您可以为外部调用提供存根。例如
val m = mock[io.Source.type]
在这里,您模拟源,然后在调用
fromUrl
函数时提供所需的行为。
即
when(m.fromUrl("external service url")) thenReturn("result")
首先,你必须用模拟注入你想要替换的依赖项,函数内的静态调用不能被模拟/存根。
在您的场景中,您还有另一个问题:您的依赖项
Source
是一个对象,并且您不能模拟对象,只能模拟非最终类和特征。此外,模拟第 3 方 API 被认为是一种不好的做法。
解决所有这些问题的一个好方法是重写代码,例如
trait HttpAdapter {
def fromUrl(apiRequestUrl: String): String = Source.fromURL(apiRequestUrl).mkString
}
object HttpAdapter extends HttpAdapter
def myFunction(apiRequestUrl: String, httpAdapter: HttpAdapter = HttpAdapter) : MyObject = {
val response: String = httpAdapter.fromUrl(apiRequestUrl)
val formatedResponse: MyObject = formatResponseFunction(response)
formatedResponse
}
"myFunction" should "work" in {
//create mock
val http = mock[HttpAdapter]
//stub mock
http.fromUrl("some url") shouldReturn "result"
//inject mock
myFunction("some url", http) shouldBe MyObject
}
注意,我已将第三方 API 包装在一个我可以完全控制的类中 (
HttpAdapter
),然后我模拟该类
然后我注入
httpAdapter
作为参数,但我提供了一个默认值,因此调用者不需要担心它,而我仍然可以在测试代码中使用模拟或存根覆盖它。
另请注意,我使用了mockito-scala而不是常规的mockito,因此存根语法是不同的。