使用PowerMock或你让你的测试对你的设计有多大影响?[已关闭]

多年来,我一直是EasyMock的粉丝,多亏了SO,我遇到了对PowerMock的引用,以及它能够模拟构造函数和静态方法的能力,这两者在将测试改造为遗留代码库时都会引起问题。

显然,单元测试(和TDD)的一个巨大好处是它导致(强制?)更干净的设计的方式,在我看来,PowerMock的引入可能会减损这一点。我认为这主要表现为:

  1. 回到初始化协作者而不是注入他们
  2. 使用静态,而不是让方法归协作者所有

除此之外,关于我的代码被为测试操作的字节码,有些事情并不完全适合我。我无法给出具体的理由,只是这让我感到有点不安,因为它只是为了测试而不是生产。

在我目前的演出中,我们真的在推动单元测试,作为人们改进编码实践的一种方式,感觉就像在等式中引入PowerMock可能会让人们跳过这一步,所以我不愿意开始使用它。话虽如此,我真的可以看到使用它可以减少开始测试类所需的重构量。

我想我的问题是,人们使用PowerMock(或任何其他类似的库)来获得这些功能的体验是什么,你会利用它们吗?你希望你的测试在多大程度上影响你的设计?


答案 1

我必须强烈反对这个问题。

没有理由使用限制设计选择的模拟工具。不仅仅是被EasyMock,EasyMock类扩展,jMock,Mockito等排除的静态方法。这些工具还可以阻止你声明类和方法,仅此一点就是一件非常糟糕的事情。(如果您需要一个权威来源来捍卫类和方法的使用,请参阅“有效的Java”一书,或观看作者的演示。finalfinal

根据我的经验,“初始化合作者而不是注入他们”通常是最好的设计。如果通过创建从某个类实例化的帮助程序类来分解某个类来解决某些复杂问题的类,则可以利用将特定数据安全地传递给这些子对象的功能,同时对客户端代码(客户端代码提供高级操作中使用的完整数据)隐藏它们。在公共 API 中公开此类帮助器类违反了信息隐藏原则,破坏了封装并增加了客户端代码的复杂性。

滥用DI会导致无状态对象,这些对象实际上应该是有状态的,因为它们几乎总是对特定于业务操作的数据进行操作。这不仅适用于非公共帮助程序类,也适用于从 UI/表示对象调用的公共“业务服务”类。此类服务类通常是内部代码(对于单个业务应用程序),它们本质上是不可重用的,并且只有几个客户端(通常只有一个),因为此类代码本质上是特定于域/用例的。在这种情况下(顺便说一句,这是一种非常常见的情况),让UI类直接实例化业务服务类,通过构造函数传递用户提供的数据,这更有意义。

能够轻松地为这样的代码编写单元测试正是促使我创建JMockit工具包的原因。我考虑的不是遗留代码,而是设计的简单性和经济性。到目前为止,我获得的结果使我确信,可测试性实际上是两个变量的函数:生产代码的可维护性,以及用于测试该代码的模拟工具的局限性。那么,如果您从模拟工具中删除所有限制,您将获得什么?


答案 2

我完全同意可测试性不是最终目标,这是我在开发PowerMock时意识到的事情之一。我也同意编写单元测试是获得良好设计的一种方式。使用PowerMock应该是一个例外而不是一个规则,至少是对构造函数的期望和静态模拟等功能。

我们使用PowerMock的主要动机是使用阻止您的代码可测试的第三方代码。一个好的替代方案是使用一个反腐败层,该层可以抽象第三方代码并使其可测试。但是,有时我认为仅使用标准API的代码更清晰。一个很好的例子是Java ME API。这充满了阻止单元测试的静态方法调用。

遗留代码也可能会出现同样的问题。一些组织非常害怕修改他们现有的代码,在这种情况下,PowerMock可用于在您目前正在编写的部分中引入单元测试,而无需强制进行大规模的重构。

我们的问题是指定一组最佳实践规则,何时使用PowerMock,新手开发人员可以遵循这些规则。创建好的设计真的很难,因为PowerMock给你更多的选择,也许对于初学者来说,它只会变得更加困难?我认为更有经验的开发人员喜欢有更多的选择。

PowerMock创始人))


推荐