据我所知,TDD的典型工作流(W1)如下:
但是,对于Meck和其他模拟框架,工作流(W2)可以是:
我倾向于认为W2比W1有一些优势:
因此,问题是:
W2真的有上述优势吗?如果不是,我如何将Meck作为一个既定的例程合并到我的日常开发中,即使用它的工作流是什么?还是我应该在没有任何指导的情况下随机使用Meck?
发布于 2012-08-23 06:15:33
不能单独使用模拟来使测试通过。如果这是可能的,那么要么您的测试不值得使用它们的名称,要么您不需要用“真正的”代码替换模拟,因为模拟已经完成了您希望代码做的事情。
模拟通常用于将被测试系统(SUT) (即要测试的类)与其依赖关系隔离开来。依赖项是模拟的,SUT不是。
发布于 2012-08-24 00:44:52
W2假设您在启动系统之前已经完成了正确的系统设计--例如,我很少进入这个职位。您必须预先进行大型设计;IME意味着您已经移动了开发过程中昂贵的部分,而不是取消它。而且,如果您的初始设计碰巧有缺陷(而且它会有缺陷),那么恢复成本就会很高。
从一开始就通过的测试是一个bug,而不是一个特性。编写特别失败的测试是关键的一步--否则您将如何证明您编写的代码实际工作?
我不能具体地与Meck交谈,但我可以讨论一般的TDD工作流,它自然地结合了各种类型的模拟对象。无论系统的其余部分是否工作,都存在允许单元测试通过的模拟对象。它们也为你接下来需要做的事情提供了自然的路标。为了使单元测试A通过,您必须模拟一个B类,很明显,接下来要做的是实现一个B类,它的模拟描述它的方式。
您的W1遗漏了一些关键步骤,包括这些步骤可能会澄清模拟对象在TDD中所扮演的角色。如伪Perl所示,TDD看起来更像这样:
while (not $project->is_feature_complete()) {
my $feature_test = write_feature_test();
die "You screwed up" if $feature_test->does_pass();
$feature_test_suite->add($feature_test);
while (not $feature_test_suite->does_pass()) {
my $test = write_unit_test();
die "You screwed up" if $test->does_pass();
$unit_test_suite->add($test);
while (not $unit_test_suite->does_pass()) {
write_exactly_enough_code_to_pass_unit_test();
while ($project->has_duplication()) {
$project->eliminate_duplication();
}
}
}
}与W1的主要区别是:
最后一点可能需要更多的放大(最好不要重复整个测试驱动的开发,比如1)。发生的情况是,进行第二次测试的最短方法通常是使用模拟对象的副本,该对象在经过一些参数调整后进行第一次测试传递。在“消除重复”步骤中,我们将这两个模拟对象组合成一个参数化对象。一旦我们重复这个循环几次,我们构建的模拟对象与我们需要的实际对象几乎是完全相同的,因此我们可以使用它的代码来实现它迄今为止隐藏的依赖关系。
在所有这些中,模拟对象的作用几乎总是一样的:允许您通过单元测试而不必同时实现整个系统。在我看来,使用它们来提前实现整个系统似乎浪费了它们的大部分效用,同时也给您带来了大前期设计的通常风险。我认为你没有得到你认为你会得到的好处;充其量,你改变了会计,从而减少了花在“编码”上的时间。
https://stackoverflow.com/questions/12085746
复制相似问题