如何模拟参数是scala中新实例的方法

How to mock a method whose parameter is a new instance in scala

我在 class:

中有一个方法
def delete(Token, Client, Scope): Future[Int]

并且此方法在另一个方法中的另一个 class 的其他地方被调用为:

acr.delete(Token(token), client, scope)

其中 tokenStringclientscope 分别是 ClientScope 的类型:

case class Client(client:   String) extends AnyVal
case class Scope(scope:     String) extends AnyVal

当我尝试在测试中模拟 delete 方法时,我这样做是:

when(mockService
            .delete(
              token      = any[Token],
              service    = any[Client],
              scope      = any[Scope]
            )
        ).thenReturn(1.toFut)

这会产生导致空指针异常的匹配异常:

Method threw 'org.mockito.exceptions.misusing.InvalidUseOfMatchersException' exception. Cannot evaluate repositories.common.Service$MockitoMock04616202.toString()

mockService 是一个 mock[Service]。我有另一个模拟方法,属于 Service 并且那个模拟不会抛出任何错误

当我逐行调试时,代码在 token = any[Token] 行失败。我不确定我还能如何使用 Matchers 并构建一个模拟。

你建议我做什么?

我假设您的代码看起来与:

case class Token(client:   String) extends AnyVal
case class Client(client:   String) extends AnyVal
case class Scope(scope:     String) extends AnyVal

class Service(implicit val ec: ExecutionContext) {
  def delete(token: Token, client: Client, scope: Scope): Future[Int] = {
    Future(1)
  }
}

对于此代码,您可以将 Token 创建为 Token[any[String]]

import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.when
import org.mockito.MockitoSugar.mock
import scala.concurrent.{ExecutionContext, Future}

implicit val ec: ExecutionContext = ExecutionContext.global
val mockService: Service = mock[Service]
when(
  mockService.delete(
    token      = Token(any[String]),
    client    = Client(any[String]),
    scope      = Scope(any[String])
  )
).thenReturn(Future(2))

此代码有效且不会引发 NPE。

我假设:您的代码抛出 NPE,因为 case 类 extends AnyVal。 来看看AnyVal源码:

abstract class AnyVal extends Any {
  def getClass(): Class[_ <: AnyVal] = null
}

它有 getClass 其中 returns null - 这听起来不是 null-safety。如果您将从您的案例 类 中删除 extends AnyVal,您的代码将起作用。可能 any 匹配器在自身内部调用 getClass,所以这是测试库的常见事情。