如何模拟参数是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)
其中 token
是 String
,client
和 scope
分别是 Client
和 Scope
的类型:
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
,所以这是测试库的常见事情。
我在 class:
中有一个方法def delete(Token, Client, Scope): Future[Int]
并且此方法在另一个方法中的另一个 class 的其他地方被调用为:
acr.delete(Token(token), client, scope)
其中 token
是 String
,client
和 scope
分别是 Client
和 Scope
的类型:
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
,所以这是测试库的常见事情。