部分嘲笑作为代码气味?

时间:2010-09-27 19:06:56

标签: java refactoring mocking partial-mocks

为什么关于'部分嘲笑'以及需要它的代码会如此讨厌呢?

这是一个(理论上的)示例实现:

public ComplexResult1 operationA(Stimulus a) {
    {
        ...
        result = ...;
    }
    auditTheChange(a);
}
public ComplexResult2 operationB(Stimulus b) {
    {
        ...
        result = ...;
    }
    auditTheChange(b);
    return result;
}
void auditTheChange(Stimulus stim) {
    // do a bunch of stuff to record the change
    // and interact with another outside service
}

现在,根据我的理解,这是重构良好的代码。

如果我想UNIT测试operationA和operationB,确保在每个场景中都进行审计,但是没有必须测试审计代码的细节,我会使用部分嘲弄。

我没有看到/理解导致如此多的项目(EasyMock,Mockito等)推荐重构?

3 个答案:

答案 0 :(得分:4)

如果审计确实是该类的内部功能,那么代码应作为单元测试的一部分进行测试。为什么你的类处理复杂的操作和审计?审计是否可以移到另一个班级?

如果是这样,请将审计作为此类的协作者介绍并嘲笑它。如果没有,请进行单元测试。

你可以使用部分嘲笑,但在这种情况下,我认为这表明课程做得太多了。

答案 1 :(得分:1)

如果auditTheChange是一个私有函数,那么您只需不编写验证其调用的测试。 您不希望单元测试与实现紧密结合。

一般来说:不要对私有方法进行单元测试

答案 2 :(得分:0)

关键点是“正在测试的单元是什么”。

许多开发人员都认为OO。在OO中,“对象”是软件的单元,因此对象也是在单元测试中测试的单元。在您的示例中,auditTheChange()是对象中的私有方法。单元测试应仅关注公共方法的行为。模拟私有方法意味着单元测试用例处理单元的一些实现细节,这被认为是“代码异味”。

一些开发人员认为软件的单位是“方法”。在您的示例中,您确实以这种方式思考。由于operationA和operationB过于紧凑,因此您可以创建auditTheChange,从而可以降低单元operationA和operationB的复杂性。如果您以这种方式考虑,则部分模拟不是“代码异味”,因为该方法是要测试的单元,而模拟私有方法也意味着“关注行为而不是实现细节”。

这里没有过时的正确或错误。这实际上取决于您的项目或团队的性质。我为公司工作,使用Spring开发企业信息系统。在Spring中,几乎所有业务逻辑都在xxxService对象中实现。当方法太复杂时,我们只是像您在示例中所做的那样,将一些逻辑移至私有方法。如果我们总是将这些逻辑移到新的类上,将会创建许多类和对象,并使程序更难以维护。因此,我们只是将逻辑移至私有方法并使用部分模拟。实际上,很多人都需要部分模拟。您可以检查此Mockito文档。最初,mockito认为部分模拟是代码异味。经过长时间的讨论和辩论,他们现在也支持部分模拟。