我正在使用 Scala 2.10、specs2 和 Mockito。我想模拟 scala.io.Source.fromURL()。问题似乎是 fromURL() is a function in io.Source's object。
val m = mock[io.Source]
m.fromURL returns io.Source.fromString("Some random string.")
这是单元测试中的一个非常简单的模拟。为什么它不起作用?
谢谢!
我正在使用 Scala 2.10、specs2 和 Mockito。我想模拟 scala.io.Source.fromURL()。问题似乎是 fromURL() is a function in io.Source's object。
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 世界中,静态方法是 mocking 的祸根。在 Scala 世界中,对对象的调用对于单元测试来说也很麻烦。但是如果你遵循上面的代码,你应该能够在你的类中正确地模拟出基于对象的依赖项。
好消息!使用最新的 1.16 版本mockito-scala
,您现在可以模拟 scala object
。
要启用 withObjectMocked 功能,必须创建包含一行的文件 src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker:
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-object
多年后,上述答案并不像其他人指出的那样起作用。
而且你不能模拟scala.io.Source
对象。
我可以模拟最终/私有方法或类吗?这是不支持的,因为使用宏生成的模拟被实现为模拟类型的子类。所以私有和最终方法不能被覆盖。您可能想尝试在代码中使用适配器或外观以使其可测试。最好针对特征/接口而不是具体实现进行测试。有一些库支持这种模拟,例如 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"
}