ScalaMock.模拟一个带有参数的类 [英] ScalaMock. Mock a class that takes arguments
问题描述
全面披露:我对模拟和模拟框架还是很陌生的.我正在尝试使用ScalaMock,因为它看起来像与ScalaTest一起使用的默认"模拟框架,但我很乐意使用与ScalaTest兼容的任何其他框架.
问题:我已经在Scala中编写了一个与套接字对话的类.该类具有要与之通信的套接字类型的类型参数,并且其参数之一是用于创建该类型套接字的工厂.它具有签名:
class XScanner[T <: SocketClient](
confPath: String = "/etc/default/configPath",
socketClientFactory: String => T
) extends ScannerBase(path)
我希望能够通过提供一个模拟SocketClient来为此类编写单元测试,这样我的测试代码不必连接到真正的套接字,但是我无法弄清楚如何使用ScalaMock做到这一点. /p>
我的测试代码如下:
val t = new XScanner[SocketClient](confPath, (s: String) => mock[SocketClient])
显然不会编译,因为SocketClient
希望将套接字的路径作为参数,但是我不能调用mock[SocketClient(s)]
,因为那不是类型,我也不能调用mock[SocketClient](s)
,因为模拟没有接受传递给它的类型的参数作为它自己的参数.
那么我该如何编写模拟SocketClient
工厂以传递给我的扫描仪?我什至无法弄清楚如何模拟一个带有参数的类!
洞察力在于,您需要模拟的是socketClientFactory
.然后将其设置为返回模拟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
没有默认值).
然后,这应该会让您入门(这与Scala 2.9.x和ScalaMock2-与ScalaMock3的2.10.x会稍有不同,但差别不大):
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中的相同测试:
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)
}
}
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.
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)
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])
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.
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!
The insight is that what you need to mock is socketClientFactory
. And then set it up to return a mock SocketClient
.
Given:
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
}
(side note - your default value for confPath
can never be used because there's no default value for socketClientFactory
).
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)
}
}
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)
}
}
这篇关于ScalaMock.模拟一个带有参数的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!