我在这里阅读了一些有关静态方法的主题,并且我认为我理解滥用/过度使用静态方法可能导致的问题。但是我并没有真正理解为什么很难模拟静态方法的原因。
我知道其他模拟框架(例如PowerMock)可以做到这一点,但为什么Mockito不能?
我读了这篇文章,但作者似乎在宗教上反对这个词static
,也许这是我的理解不周。
一个简单的解释/链接会很好。
我在这里阅读了一些有关静态方法的主题,并且我认为我理解滥用/过度使用静态方法可能导致的问题。但是我并没有真正理解为什么很难模拟静态方法的原因。
我知道其他模拟框架(例如PowerMock)可以做到这一点,但为什么Mockito不能?
我读了这篇文章,但作者似乎在宗教上反对这个词static
,也许这是我的理解不周。
一个简单的解释/链接会很好。
Answers:
我认为原因可能是模拟对象库通常通过在运行时动态创建类(使用cglib)来创建模拟。这意味着他们要么在运行时实现一个接口(如果我没有记错,那就是EasyMock所做的事情),或者他们从要继承的类继承(如果我没记错的话,那就是Mockito所做的事情)。这两种方法都不适用于静态成员,因为您不能使用继承来覆盖它们。
模拟静态变量的唯一方法是在运行时修改类的字节码,我想这比继承要复杂得多。
这就是我的猜测,这是值得的...
如果您需要模拟静态方法,则可以很好地指示不良设计。通常,您要模拟被测类的依赖关系。如果您的被测类是指静态方法(例如java.util.Math#sin),则意味着被测类正是需要此实现(例如,准确性与速度)。如果您想从一个具体的窦性实施中抽象出来,您可能需要一个接口(您知道它要去哪里)?
如果您也需要模拟静态方法,我确实认为这是代码气味。
在我看来,唯一一次似乎过大的问题是像Guava这样的库,但是无论如何您都不必模拟这种类型,因为它是逻辑的一部分...(像Iterables.transform(..)之类的东西)
那样,您自己的代码保持整洁,您可以以整洁的方式模拟出所有依赖项,并且拥有一个针对外部依赖项的反腐败层。我已经在实践中看到了PowerMock,而我们所需的所有课程的设计都不尽人意。此外,PowerMock的集成有时会引起严重的问题
(例如https://code.google.com/p/powermock/issues/detail?id=355)
PS:私有方法也是如此。我认为测试不应该了解私有方法的细节。如果一个类太复杂以至于它倾向于模拟私有方法,那可能是一个分裂该类的信号。
@Inject SomeDependency
和配置中,我定义了bind(SomeDependency.class).in(Singleton.class)
。因此,如果明天不再是Singleton,我更改一个配置,就是这样。
Foo.getInstance()
到处打电话。我只是在答案中写了singleton来对抗参数“但静态方法不需要创建许多包装对象”。从概念上讲,对我来说,单例上的静态方法和实例方法之间也没有什么区别,只是您无法模拟该单例协作者。但是,单身与否绝对不是我要讲的重点,重点是注入和模拟协作者,如果难以进行测试,则不要调用静态方法。
在某些情况下,静态方法可能很难测试,尤其是在需要模拟它们的情况下,这就是为什么大多数模拟框架都不支持它们的原因。我发现这篇博客文章对于确定如何模拟静态方法和类非常有用。