斯卡拉模拟.模拟一个接受参数的类 [英] ScalaMock. Mock a class that takes arguments

查看:19
本文介绍了斯卡拉模拟.模拟一个接受参数的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

完全披露:我对模拟和模拟框架非常陌生.我正在尝试使用 ScalaMock,因为它看起来像是与 ScalaTest 一起使用的默认"模拟框架,但我很乐意使用与 ScalaTest 兼容的任何其他框架.

Full disclosure: I'm very new to mocking and mocking frameworks. I'm trying to use ScalaMock because it seemed like the 'default' mocking framework to use with ScalaTest but I am happy to use any other framework which is compatible with ScalaTest.

问题:我用 Scala 编写了一个与套接字对话的类.该类有一个类型参数,说明它要与之交谈的套接字类型,其中一个参数是用于创建该类型套接字的工厂.它有签名:

The problem: I've written in Scala a class that talks to a socket. The class has a type parameter of what sort of socket it is to talk to and one of it's arguments is a factory for creating sockets of that type. It has the signature:

class XScanner[T <: SocketClient](
  confPath: String = "/etc/default/configPath",
  socketClientFactory: String => T
) extends ScannerBase(path)

我希望能够通过提供一个模拟 SocketClient 来为这个类编写单元测试,这样我的测试代码就不必连接到一个真正的套接字,但我不知道如何使用 ScalaMock 来做到这一点.

I would like to be able to write unit tests for this class by supplying a mock SocketClient so my test code doesn't have to connect to a real socket but I can't work out how to do this with ScalaMock.

我的测试代码如下所示:

My test code looks like this:

val t = new XScanner[SocketClient](confPath, (s: String) => mock[SocketClient])

显然这不会编译,因为 SocketClient 需要一个套接字路径作为参数,但我不能调用 mock[SocketClient(s)] 因为那不是一个类型,我不能调用 mock[SocketClient](s) 因为 mock 不会将传递给它的类型的参数作为它自己的参数.

Clearly that won't compile because SocketClient expects a path to the socket as an argument but I can't call mock[SocketClient(s)] because that's not a type and I can't call mock[SocketClient](s) because mock doesn't take the arguments of the type passed to it as it's own arguments.

那么我如何编写一个模拟 SocketClient 工厂来传递给我的 Scanner?我什至不知道如何模拟一个带参数的类!

So how can I write a mock SocketClient factory to pass to my Scanner? I can't even work out how to mock a class that takes arguments!

推荐答案

洞察力是你需要模拟的是 socketClientFactory.然后将其设置为返回一个模拟 SocketClient.

The insight is that what you need to mock is socketClientFactory. And then set it up to return a mock SocketClient.

给定:

trait SocketClient {
  def frobnicate(): Unit
}

class ScannerBase(path: String)

class XScanner[T <: SocketClient](
  confPath: String = "/etc/default/configPath",
  socketClientFactory: String => T
) extends ScannerBase(confPath) {
  val socket = socketClientFactory("Some Socket Name")
  socket.frobnicate
}

(旁注 - 您的 confPath 的默认值永远无法使用,因为 socketClientFactory 没有默认值).

(side note - your default value for confPath can never be used because there's no default value for socketClientFactory).

那么这应该可以帮助您入门(这是 Scala 2.9.x 和 ScalaMock2 - ScalaMock3 的 2.10.x 会略有不同,但差别不大):

then this should get you started (this is with Scala 2.9.x and ScalaMock2 - 2.10.x with ScalaMock3 will be slightly different, but not much so):

import org.scalatest.FunSuite
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory

class ScannerTest extends FunSuite with MockFactory with GeneratedMockFactory {

  test("scanner") {
    val mockFactory = mockFunction[String, SocketClient]
    val mockClient = mock[SocketClient]
    mockFactory.expects("Some Socket Name").returning(mockClient)
    mockClient.expects.frobnicate
    val scanner = new XScanner("path/to/config", mockFactory)
  }
}

为了完整起见,以下是 Scala 2.10.0 和 ScalaMock3 中的相同测试:

For completeness, here's the same test in Scala 2.10.0 and ScalaMock3:

import org.scalatest.FunSuite
import org.scalamock.scalatest.MockFactory

class ScannerTest extends FunSuite with MockFactory {

  test("scanner") {
    val mockFactory = mockFunction[String, SocketClient]
    val mockClient = mock[SocketClient]
    mockFactory.expects("Some Socket Name").returning(mockClient)
    (mockClient.frobnicate _).expects()
    val scanner = new XScanner("path/to/config", mockFactory)
  }
}

这篇关于斯卡拉模拟.模拟一个接受参数的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆