我目前正在研究Scala项目,并且在测试广泛使用Singleton对象的代码时遇到困难。
我有这样的单身人士:
object SomeSingleton {
def someFunction(s: String): String = s + "b"
}
在项目中的某处,我可以在要测试的方法中使用它:
val s = SomeSingleton.someFunction("a")
我开发了新功能,并且我希望
SomeSingleton.someFunction
在测试中返回某个特定值而没有真正的方法调用,我在Java中使用Powermock做到了这一点,但是我没有找到在Scala中做到这一点的方法。我有一个想法,我仍然可以做到这一点,但这意味着将原始代码更改为此:
object SomeSingleton extends SomeSingletonClass{}
class SomeSingletonClass {
// Whole logic from SomeSingleton moves here
def someFunction(s: String): String = s + "b"
}
现在,我可以将
SomeSingleton
的用法替换为SomeSingletonClass
并对其进行适当的模拟。所以这是我的担忧,该项目规模不小,没有100%进行测试,而且我对Scala还是比较陌生的,所以我不确定,它会导致任何不良后果吗?这是可行的解决方案吗?因此,我不希望我的旧代码在某个随机位置中断。 最佳答案
给定您所拥有的(具有很多单例的遗留代码),我认为您的解决方案可能还可以。我想在这里分享我的一些想法。
是的,引入SomeSingletonClass
类将有助于模拟该类,但是缺点是它不再是单例。我可以轻松地执行val newSingleton = new SomeSingletonClass()
,瞧,我创建了一个新对象。知道,测试单例的最佳方法是直接测试单例。我想您的单例将调用更多其他单例,并且您不想执行所有这些副作用。但是要正确解决问题,您将需要大量重构代码。PowerMock
是Java中非常强大的模拟工具(可能功能太多)。它可以模拟静态方法/单例的方式是修改字节码。它在大多数情况下都可以使用,但是当它不起作用时,您绝对不知道如何修复它。在我之前在Amazon的工作中,我们曾经广泛使用PowerMock,但是由于它的黑匣子魔力,我们逐渐远离它。帮助我们实现这一目标的一种方法是使用依赖项注入,您可以轻松地在测试中注入模拟对象。
我可以看到您正在处理旧版代码,因此要重写所有内容并不容易(例如,引入依赖项注入,甚至是您尝试在此处尝试的新SomeSingletonClass
)。我的建议是,您可能不应该花太多时间为遗留代码编写测试。相反,在编写新代码时,请尝试使其可测试,并根据需要重构旧代码。