我使用的是Scala 2.10、specs2和Mockito。我想模拟scala.io.Source.fromURL((。问题似乎是fromURL((是io.Source对象中的一个函数。
val m = mock[io.Source]
m.fromURL returns io.Source.fromString("Some random string.")
这是单元测试中非常简单的模拟。为什么它不起作用?
谢谢!
与其嘲笑它,不如按如下方式尝试spying
:
val m = spy(io.Source)
或者你可以嘲笑它如下:
val m = mock[io.Source.type]
但是,在测试的类中,你是如何使用Source
的呢?如果你有一个这样的示例类:
class MyClass{
def foo = {
io.Source.doSomething //I know doSomething is not on Source, call not important
}
}
然后,为了利用嘲笑/间谍,你必须这样构建你的类:
class MyClass{
val source = io.Source
def foo = {
source.doSomething
}
}
然后你的测试必须看起来像这样:
val mockSource = mock[io.Source.type]
val toTest = new MyClass{
override val source = mockSource
}
在Java世界中,静态方法是嘲讽的祸根。在Scala的世界里,对对象的调用对于单元测试来说也很麻烦。但是,如果您遵循上面的代码,您应该能够在类中正确地模拟出基于对象的依赖关系。
好消息!有了mockito-scala
的最新1.16版本,您现在可以模拟scala object
s。
要启用ObjectMocked功能,必须创建文件src/test/resources/mockito-extensions/org.mockito.plugins.LockMaker,其中包含一行:
mock-maker-inline
示例:
object FooObject { def simpleMethod: String = "not mocked!" } "mock" should { "stub an object method" in { FooObject.simpleMethod shouldBe "not mocked!" withObjectMocked[FooObject.type] { FooObject.simpleMethod returns "mocked!" //or when(FooObject.simpleMethod) thenReturn "mocked!" FooObject.simpleMethod shouldBe "mocked!" } FooObject.simpleMethod shouldBe "not mocked!" } }
请参阅:https://github.com/mockito/mockito-scala#mocking-scala对象
多年后,上面的答案并没有像其他人所指出的那样奏效。
并且不能模拟scala.io.Source
对象。
我可以模拟final/private方法或类吗?这是不受支持的,因为用宏生成的mock被实现为要mock的类型的子类。因此,私有方法和最终方法不能被重写。您可能想尝试在代码中使用适配器或外观,使其可测试。最好针对特性/接口进行测试,而不是针对具体实现进行测试。有一些库支持这种嘲讽,比如PowerMock。请注意,这种嘲讽涉及字节码操作,这有可能导致您的测试与实际实现产生双重差异。
因此,我所做的是将scala.io.Source.fromUrl()
抽象为函数参数,并在测试中传递模拟函数。
// original func
def aFuncThatUsesSource() = {
val source = scala.io.Source("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
// test friendly func that accepts `scala.io.Source.fromURL` as arg
def aTestFriendlyFunc(makeApiCall: String => BufferedSource) = {
val source = makeApiCall("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
....
// test spec
def testyMcTesterson = () => {
val makeApiCall = mockFunction[String, BufferedSource]
makeApiCall.expects("something...")
.returns( new BufferedSource(new ByteArrayInputStream("returns something".getBytes)) )
aTestFriendlyFunc(makeApiCall) shouldEqual "returns something"
}