Scala:如何对我使用模拟/存根进行API调用的函数进行单元测试?

时间:2018-11-14 23:09:07

标签: scala unit-testing mocking

我有一个函数可以对外部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的函数调用

2 个答案:

答案 0 :(得分:1)

对于模拟外部服务调用,您可以使用Mockito,这是一个模拟框架。 Mockito非常易于使用,您可以为外部呼叫提供存根。例如

val m = mock[io.Source.type]

在这里模拟源代码,然后在调用fromUrl函数时提供所需的行为。 即

when(m.fromUrl("external service url")) thenReturn("result")

答案 1 :(得分:1)

首先,您必须注入要用模拟替换的依赖项,不能对函数内的静态调用进行模拟/存根

在方案中,您还有另一个问题:依赖项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,因此存根语法是不同的