21

是否应该在单元测试开发环境中使用静态类/方法/属性,因为如果不引入再次不可测试的包装器就无法对其进行测试?

另一种情况是,当在单元测试目标中使用静态成员时,无法模拟静态成员。因此,您必须在测试单元测试目标时测试静态成员。您希望在静态成员执行计算时将其隔离。

4

5 回答 5

49

测试静态方法与测试任何其他方法没有什么不同。将静态方法作为另一个测试模块中的依赖项会引发问题(正如已经提到的 - 您不能使用免费工具模拟/存根它)。但是,如果静态方法本身经过单元测试,您可以简单地将其视为有效的、可靠的组件

总体而言,在以下情况下,使用静态方法没有任何问题(例如,它不会破坏单元测试/TDD):

  • 它很简单,输入输出方法(各种“计算这个给定”
  • 它是可靠的,我们的意思是它要么是由您进行单元测试,要么来自您认为可靠的第 3 方来源(例如,Math.Floor可能被认为是可靠的 - 使用它不应该引发“小心,它是静态的!”警告;人们可能会假设微软完成了它的工作)

什么时候静态方法会导致问题并且应该避免?基本上只有当他们与你无法控制(或模拟)的事情交互/做一些事情时:

  • 各种文件系统、数据库、网络依赖
  • 从内部调用的其他(可能更复杂的)静态方法
  • 几乎所有你的模拟框架不能正常处理的事情

编辑: 关于静态方法何时会使单元测试变得困难的两个示例

1

public int ExtractSumFromReport(string reportPath)
{
     var reportFile = File.ReadAllText(reportPath);
     // ...
}

你怎么处理File.ReadAllText?这显然会去文件系统检索文件内容,这是单元测试时的主要禁忌。这是具有外部依赖关系的静态方法的示例。为避免这种情况,您通常会围绕文件系统 api 创建包装器,或者只是将其作为依赖项/委托注入。

2

public void SaveUser(User user)
{
    var session = SessionFactory.CreateSession();
    // ...
}

那这个呢?会话是非平凡的依赖。当然,它可能会出现ISession,但是如何强制SessionFactory返回模拟?我们不能。而且我们也不能创建容易确定的会话对象。

在上述情况下,最好完全避免使用静态方法。

于 2012-05-17T09:35:07.197 回答
3

静态方法可以进行单元测试。它们不能被嘲笑(通常;有一些框架可以做到这一点,比如Moles

于 2012-05-17T09:28:59.837 回答
1

您不能模拟静态方法/属性。因此,当您classA使用某些静态成员时,classB您无法单独进行测试classA

更新:我没有看到将一些静态类包装到对象中的任何问题。它不需要很多时间,但它可以让您减少系统中的耦合。

于 2012-05-17T09:28:32.210 回答
0

从技术上讲,您可以使用PowerMock模拟 Java 中的静态方法,但如果您需要这样做,我强烈建议您重构您的代码。我认为静态方法应该总是private并且只在它们定义的类中使用,用于内部目的。我认为公开暴露的静态方法是一种代码异味

于 2012-05-21T20:08:40.897 回答
0

无论编程语言如何,我都发现了这种威胁,但由于我的日常生活与 PHP 有关,这里是处理 PHP 上的静态方法的好资源http://docs.mockery.io/en/latest/reference/public_static_properties.html

于 2018-06-18T21:48:13.970 回答