tdd - 我应该在这里模拟还是使用真正的实现

时间:2011-06-27 19:52:06

标签: unit-testing tdd mocking

我正在编写程序参数解析器,只是为了在TDD中变得更好,我坚持以下问题。假设我的解析器定义如下:

class ArgumentsParser {
    public ArgumentsParser(ArgumentsConfiguration configuration) {
        this.configuration = configuration;
    }

    public void parse(String[] programArguments) {
        // all the stuff for parsing
    }
}

我希望ArgumentsConfiguration实现如下:

class ArgumentsConfiguration {
    private Map<String, Class> map = new HashMap<String, Class>();

    public void addArgument(String argName, Class valueClass) {
        map.add(argName, valueClass);
    }

    // get configured arguments methods etc.
}

这是我目前的阶段。目前在测试中我使用:

@Test
public void shouldResultWithOneAvailableArgument() {
    ArgumentsConfiguration config = prepareSampleConfiguration(); 
    config.addArgument("mode", Integer.class);
    ArgumentsParser parser = new ArgumentsParser(configuration);
    parser.parse();
    // ....
}

我的问题是这样的方式是否正确?我的意思是,在测试中使用真正的ArgumentsConfiguration是否可以?或者我应该嘲笑它?默认(当前)实现非常简单(只是包装Map),但我想它可能更复杂,比如从数据源类型中获取配置。然后,很自然地嘲笑这样的&#34;昂贵的&#34;行为。但这里有什么首选方式?

编辑: 也许更清楚:我是否应该模拟ArgumentsConfiguration,即使没有编写任何实现(只是定义它的公共方法),使用mock进行测试并稍后处理实际实现,或者我应该在测试中使用最简单的实现,并让它们覆盖这个间接实施。但如果是这样,那么测试后面提供的另一个配置实现呢?

3 个答案:

答案 0 :(得分:5)

  

然后嘲笑这种“昂贵”的行为是很自然的。

这不是重点。你不是在嘲笑复杂的课程。

你嘲笑完全隔离课程。

完全隔离确保测试证明类遵循其接口并且没有隐藏的实现怪癖。

此外,完全隔离使得调试失败的测试变得更加容易。它可以是测试,被测试的类或模拟对象。理想情况下,测试和模拟非常简单,不需要任何调试,只留下测试类。

答案 1 :(得分:5)

正确的答案是你应该模拟任何你不想直接测试的东西(例如:被测对象与特定测试用例不直接相关的任何依赖项)。

答案 2 :(得分:0)

在这种情况下,因为您的ArgumentsConfiguration非常简单,所以我建议您使用真正的实现,直到您的需求变得更复杂。您的ArgumentsConfiguration类中似乎没有任何逻辑,因此使用真实对象是安全的。如果时间到了配置更复杂的时候,那么您应该采取的方法不是创建与某些数据源对话的配置,而是从该数据源生成ArgumentsConfiguration对象。然后你可以进行测试,确保它从数据源正确生成配置,你不需要不必要的抽象。