我正在编写程序参数解析器,只是为了在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进行测试并稍后处理实际实现,或者我应该在测试中使用最简单的实现,并让它们覆盖这个间接实施。但如果是这样,那么测试后面提供的另一个配置实现呢?
答案 0 :(得分:5)
然后嘲笑这种“昂贵”的行为是很自然的。
这不是重点。你不是在嘲笑复杂的课程。
你嘲笑完全隔离课程。
完全隔离确保测试证明类遵循其接口并且没有隐藏的实现怪癖。
此外,完全隔离使得调试失败的测试变得更加容易。它可以是测试,被测试的类或模拟对象。理想情况下,测试和模拟非常简单,不需要任何调试,只留下测试类。
答案 1 :(得分:5)
正确的答案是你应该模拟任何你不想直接测试的东西(例如:被测对象与特定测试用例不直接相关的任何依赖项)。
答案 2 :(得分:0)
在这种情况下,因为您的ArgumentsConfiguration非常简单,所以我建议您使用真正的实现,直到您的需求变得更复杂。您的ArgumentsConfiguration类中似乎没有任何逻辑,因此使用真实对象是安全的。如果时间到了配置更复杂的时候,那么您应该采取的方法不是创建与某些数据源对话的配置,而是从该数据源生成ArgumentsConfiguration对象。然后你可以进行测试,确保它从数据源正确生成配置,你不需要不必要的抽象。