17

当您尝试在项目中实现单元测试时,我一直在阅读静态方法、静态类和单例是邪恶的。当遵循 TDD 范式时,我应该忘记它们曾经存在并且不再使用它们,还是有时可以使用它们?

4

4 回答 4

10

永远不要说永远——静态类和方法在您的工具箱中占有一席之地。

也就是说,如果您尝试隔离和测试的类(被测对象或 SUT)依赖于静态类或方法,您将无法编写将 SUT 与该静态依赖项隔离的测试——当您的测试代码运行它仍然会使用静态调用。有时这很好,但有时您想创建一个孤立的测试,仅测试您的 SUT 的逻辑而没有依赖关系(通常通过模拟或类似技术)。

一般来说,我个人比较谨慎地使用静态类和方法。

由于 Singleton 实现方式的性质,它们在隔离 SUT 以进行单元测试时存在类似的问题。此外,GOF 单例概念被一定比例的软件开发人员认为是一种不好的做法。我碰巧同意这种观点,但在这个问题上几乎没有共识。在 google 上快速搜索一下,您可能会对 GOF Singleton 模式的优缺点有一个很好的了解。

于 2011-03-30T13:16:12.573 回答
3
  1. 你应该忘记他们曾经存在过吗?不。
  2. 您是否应该确保以对类的功能透明的方式将它们合并到您的代码中?是的。

为了进一步解释最后一部分,不要尝试从代码中的单例中检索值,而是尝试在构造函数参数中初始化该值。如果你的构造函数变得太大,创建一个工厂方法来创建,这样你就可以在不使用单例的情况下测试你的类。如果这被证明是有问题的,或者您的单例具有可变状态(我会害怕,但嘿,就是我)然后尝试拥有它,以便您的单例尽可能容易地融入您的测试中。

您不希望创建一个完整的配置文件只是为了测试一个类上的一个方法,该类计算一个股票报价块在 4 小时内的标准偏差。那工作量太大了。但是,如果您的单例以这样一种方式编写,您可以用数据填充它并让另一个类负责读取配置文件并填充该数据,那么您已经取得了长足的进步。

关于静态方法,我认为它们是您可以编写的最容易测试的方法,前提是您无需担心全局状态。静态等价于y = f(x)看起来简单但没有本地状态转换可以改变不变的事实,对于给定的x你总是会得到相同的y

于 2011-03-30T13:08:48.257 回答
2

与任何软件工程实践一样,对于任何情况都没有一个明确的解决方案。所以你永远不应该排除静态方法、静态类和单例。TDD 的目的是让您的生活更轻松,您会注意到,随着您更多地使用 TDD,您的代码将是模块化的,这意味着即使您使用静态方法(...等),您的代码仍然是可测试的。

我喜欢遵循的规则是:使用任何你想要的东西,只要你的代码易于阅读并且你的设计优雅。如何实现这两个取决于您。哎呀,如果您仍然可以提供优雅的代码,那么您不妨使用 GOTO。

于 2011-03-30T13:02:44.517 回答
-2

我一直在阅读静态方法......当您尝试实施单元测试时是邪恶的

我从来没有读过那个。你能提供一个参考吗?我会对此提出异议。我一直在使用和单元测试静态方法(函数),而且没有问题。


已编辑

感谢您对静态方法的参考是可测试性的死亡:那篇文章是垃圾。

静态方法的基本问题是它们是过程代码。我不知道如何对程序代码进行单元测试。

这表明作者对单元测试知之甚少。当然,您可以对过程代码进行单元测试。

在实例化期间,我将依赖项与替换真正依赖项的模拟/友好连接。

这是关键错误:单元测试需要模拟对象的想法。它不是。在任何情况下,您都可以将模拟对象作为参数传递给您正在测试的静态方法:依赖注入不需要构造函数。有关更多信息,请参阅问题“静态方法:何时以及何时不”的已接受答案

如果静态方法调用另一个静态方法,则无法覆盖调用的方法依赖项。

真实但无关紧要。如果静态方法A调用静态方法B,那就是方法A的实现细节。因此,您没有任何业务试图拦截对B的呼叫。只需将A视为一个单位。

假设您的应用程序只有静态方法

稻草人论据。显然,在现代单元测试的上下文中,我们谈论的是一个只有一些静态方法的 OO 程序。

于 2011-03-30T13:13:50.393 回答