我读到过一些关于在项目中实现单元测试时,静态方法,静态类和单例模式是有问题的。当遵循TDD范例时,我应该忘记它们并且永远不再使用它们吗?还是有时可以使用它们?
我读到过一些关于在项目中实现单元测试时,静态方法,静态类和单例模式是有问题的。当遵循TDD范例时,我应该忘记它们并且永远不再使用它们吗?还是有时可以使用它们?
永远不要说永远——静态类和静态方法在您的工具箱中有其用处。
然而,如果您正在尝试隔离和测试的类(测试主题或SUT)依赖于静态类或方法,则无法编写可以将SUT与静态依赖项隔离的测试——当您的测试代码运行时,它仍将使用静态调用。有时这是可以接受的,但有时您想创建一个隔离的测试,仅测试您的SUT逻辑而没有依赖关系(通常通过模拟或类似技术)。
总体上,我个人相对节俭地使用静态类和方法。
由于单例的实现方式,它们对于隔离SUT进行单元测试也存在类似的问题。此外,GOF单例模式的概念被认为是某些软件开发人员的一种不良实践。我碰巧同意这种观点,但在这个问题上几乎没有共识。在谷歌上快速搜索可能会让你对GOF单例模式的优缺点有一个相当好的了解。
为了进一步解释上述内容,与其在代码中尝试从单例中检索值,不如在构造函数参数中初始化该值。如果构造函数变得过于庞大,可以创建一个工厂方法进行创建,这样可以在不使用单例的情况下测试类。如果这种方法有问题或者您的单例具有可变状态(我会感到惊恐,但是那是我的个人意见),那么请尽量让您的单例易于集成到您的测试中。
您不希望为了测试一个计算股票报价块的标准差的类中的方法而创建整个配置文件。那太麻烦了。但是,如果您的单例被编写成可以填充数据,并且另一个类负责读取配置文件并填充该数据,则您已经取得了巨大的进展。
关于静态方法,我认为它们是最容易测试的方法,前提是您不需要担心全局状态。静态方法相当于y = f(x)
,虽然看起来很简单,但这表明对于给定的x
,您将始终得到相同的y
,而且没有局部状态转换能够改变这一不变量。
与任何软件工程实践一样,没有一种明确的解决方案适用于所有情况。因此,您不应排除静态方法、静态类和单例模式。TDD的目的是使您的生活更轻松,您会发现随着使用TDD的次数增多,您的代码将是模块化的,这意味着即使您使用静态方法(...等等),您的代码仍然可以进行测试。
我喜欢遵守的规则是:只要您的代码易于阅读且设计优雅,您就可以使用任何东西。如何实现这两点取决于您。如果您仍然能够交付优雅的代码,那么您甚至可以使用GOTO语句。
编辑
谢谢提到静态方法对可测试性的杀伤力的参考文献: 那篇文章真是一派胡言。
静态方法的基本问题在于它们是过程化代码。我不知道如何单元测试过程化代码。
这表明作者对单元测试了解有限。当然你可以对过程化代码进行单元测试。
在实例化过程中,我使用模拟/友好对象来替换真实依赖项进行依赖注入。
这是一个关键的错误观点:认为单元测试需要使用模拟对象。事实并非如此。无论如何,你可以将模拟对象作为参数传递给正在测试的静态方法:依赖注入并不需要构造函数。更多信息,请参阅问题“静态方法:何时使用,何时不使用”的被接受答案
如果静态方法调用另一个静态方法,就无法覆盖被调用方法的依赖项。
虽然正确但不相关。如果静态方法A调用静态方法B,那就是方法A的实现细节。所以你没有理由试图拦截对B的调用。只需将A视为一个单元。
假设您的应用程序除了静态方法之外什么都没有
这是一个草人论点。显然,在现代单元测试的背景下,我们正在谈论仅具有一些静态方法的OO程序。