【问题标题】:Unit testing with mock that has mock inside使用内部有模拟的模拟进行单元测试
【发布时间】:2017-03-17 14:17:33
【问题描述】:

我需要对适用于 X 类型对象的某个方法进行单元测试。X 对象有很少的普通字段,如 String、int 等,但它也有一个 Y 类型列表。这种 Y 类型也很复杂.为了让我的问题更加困难,假设 Y 类型有另一个 Z 类型列表。

理想情况下,我需要模拟对象 X,但告诉它在内部注入另一个类型为 Y 的模拟,它也应该向自身(对 Y)注入另一个模拟 Z。我该怎么做?

如果我有这么多少级别的模拟,我应该如何避免编写 20 个规范来说明这些模拟在调用它们的方法时应该实际返回什么?

或者这是一种我应该使用构建器并实际构建真实对象的问题?

非常感谢, 鲍勃。

编辑: 只是我脑海中的示例用法代码:

public String produceImportantStringOfImportantData(ObjectX x) throws ParseException {
    StringBuilder textResult = new StringBuilder();

    List<ObjectY> listOfY = x.getListOfY();

    if (listOfY.isValid()) {
        for (ObjectY y : listOfY) {
            for (ObjectZ z : y.getListOfZ()) {
                textResult.append("<font color='green'>").append(z.getField2).append("</font>").append(": ").append(z.getSomething())
                        .append(" Label : ").append(z.getParentComponent.getField()))
                        .append(" some important labels: ").append(z.getField()))
                        .append(" some important labels ").append(y.getAnotherField))
                        .append(" different, important label: ").append(y.getField()))
                        .append("<br/>");
            }
        }
    } 
    return textResult.toString();
}

【问题讨论】:

  • 请展示一个代码示例。
  • 手动连接的 HTML 是邪恶的。 &lt;font&gt; 标签也是如此。又是 1997 年吗?

标签: java unit-testing


【解决方案1】:

假设您正在使用像 Mockito 这样的模拟框架,您可以这样做:

X mockX = Mockito.mock(X.class);
Y mockX = Mockito.mock(Y.class);
Z mockX = Mockito.mock(Z.class);
Mockito.when(mockY.getZ()).thenReturn(mockZ);
Mockito.when(mockX.getY()).thenReturn(mockY);

如果这太深了(您提到了 20 个规范),则可能表明您违反了 Law of DemeterSingle Responsibility Principle。在这种情况下,这意味着您的类自己执行了太多逻辑,而不是在其构造函数中接受一些执行实际工作的处理器。

如果您愿意这样做,您可以轻松地单独测试处理器,并测试整个过程。

【讨论】:

    【解决方案2】:

    请不要为此使用模拟,因为绝对没有必要,但正如您似乎已经意识到的那样,这会导致痛苦和脆弱的测试。

    或者这是一种我应该使用构建器并实际构建真实对象的问题?

    您甚至不需要 Builder(尽管我确实推荐它们) - 只需使用真实对象即可。使用真实对象会导致测试必须更有弹性地进行重构,将测试您的代码实际在做什么,而不仅仅是您认为的。

    【讨论】:

    • 我不同意:当未测试的代码发生更改时,使用真实代码会导致单元测试失败,从而使测试对本应免疫的更改敏感。
    • 如果你设计的测试不好,它会是的。 OP 正在谈论使用价值对象,而不是可以以弹性方式播种的合作者。模拟是一种替代在测试中使用困难和/或缓慢的协作者的方法 - 而不是将每个人与其他所有事物完全隔离的方法
    猜你喜欢
    • 2013-07-08
    • 2011-05-13
    • 2020-01-03
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 2018-09-04
    • 2013-11-12
    • 2018-11-21
    相关资源
    最近更新 更多