此答案仅使用 scalatest 并且不影响源代码:
基本解决方案:
假设你有这个 src 类(你想要测试并且你想要模拟依赖的那个):
package com.my.code
import com.lib.LibHelper
class MyClass() {
def myFunction(): String = LibHelper.help()
}
和这个库依赖(你想在测试 MyClass 时模拟/覆盖):
package com.lib
object LibHelper {
def help(): String = "hello world"
}
这个想法是在您的测试文件夹中创建一个类,它将覆盖/隐藏库。该类将与您要模拟的类具有相同的名称和相同的包。在src/test/scala/com/external/lib
中,您可以创建LibHelper.scala
包含以下代码的内容:
package com.lib
object LibHelper {
def help(): String = "hello world - overriden"
}
这样你就可以用通常的方式测试你的代码:
package com.my.code
import org.scalatest.FunSuite
class MyClassTest extends FunSuite {
test("my_test") {
assert(new MyClass().myFunction() === "hello world - overriden")
}
}
改进的解决方案,允许为每个测试设置模拟行为:
以前的代码清晰简单,但 LibHelper 的模拟行为对于所有测试都是相同的。并且可能希望 LibHelper 的一种方法产生不同的输出。因此,我们可以考虑在 LibHelper 中设置一个可变变量,并在每次测试之前更新该变量,以便设置 LibHelper 所需的行为。(这仅在 LibHelper 是一个对象时才有效)
阴影 LibHelper(在 src/test/scala/com/external/lib 中的那个)应该替换为:
package com.lib
object LibHelper {
var testName = "test_1"
def help(): String =
testName match {
case "test_1" => "hello world - overriden - test 1"
case "test_2" => "hello world - overriden - test 2"
}
}
并且最大规模的类应该变成:
package com.my.code
import com.lib.LibHelper
import org.scalatest.FunSuite
class MyClassTest extends FunSuite {
test("test_1") {
LibHelper.testName = "test_1"
assert(new MyClass().myFunction() === "hello world - overriden - test 1")
}
test("test_2") {
LibHelper.testName = "test_2"
assert(new MyClass().myFunction() === "hello world - overriden - test 2")
}
}
非常重要的精度,因为我们使用的是全局变量,所以强制 scalatest 按顺序(而不是并行)运行测试是强制性的。相关的 scalatest 选项(将包含在 build.sbt 中)是:
parallelExecution in Test := false