由于我的应用程序域的数据结构最近变得相当复杂,所以我开始阅读模拟对象。很快,一个简单的问题出现在我的脑海中,但到目前为止,答案已经被证明是相当令人头疼的。所以这里是这样的:
我们有一个'Foo‘类,它的方法之一是'bar’:
class Foo {
public String bar(int i){
if(i == 1) return "arrr!";
}
}
我们有一个叫做Foo.bar(1)的盗版类,在它的一个方法中:
class Pirate {
public String yell(){
Foo foo = new Foo();
return foo.bar(1);
}
现在我们在Pirate类的单元测试中模拟Foo类,因为Foo恰好有太多的其他依赖项:
@Test
public void returnsPirateString() {
Pirate blackBeard = new Pirate();
Foo fooMock = mock(Foo.class);
fooMock.expectAndReturn("bar",1,"arrr!"); //expects 'bar' function to be called once and returns "arrr!"
assertEquals(blackBeard.yell(),"arrr!");
}
现在发生的情况是,如果我们重构方法bar以返回null而不是"arrr!",我们的测试将继续愉快地运行,而我们的程序不会以我们想要的方式工作。这可能会导致可能的调试噩梦。
使用mockist方法而不是经典的测试方法进行单元测试,大多数时候所有的"helper“对象都会被模仿,只有被测试的对象保持未模仿状态,所以前面提到的问题也会经常发生。
如何在模拟时防止此问题?
发布于 2010-09-30 14:31:13
你也应该隔离测试“辅助对象”。一旦覆盖并测试了这两种方法,您就可以确保它们以预期的方式进行交互。
更改您的“辅助对象”应该通过对该辅助对象进行测试来确认它仍按预期运行。
如果您关心帮助器和主类组合的特定运行时行为,那么您应该使用集成测试或更高级别的其他测试来断言这两者可以按预期协同工作。
发布于 2010-09-30 14:31:46
在测试中,您将测试使用Foo的Pirate类的yell()方法。因此,您必须模拟Foo的bar方法的行为。为了确保bar方法正常工作,您需要另一个测试用例来测试Foo的bar方法。
@Test
public void testBar() {
//make sure bar retrun "arrr"!
}
现在,如果您的bar方法返回null,则此测试用例将失败!
发布于 2010-09-30 14:49:22
测试returnsPirateString
不是假阳性--它测试当Pirate
的Foo
实例返回'arrr!‘时会发生什么。
换句话说,当您测试Pirate.yell
时,Foo.bar
返回什么并不重要,除非它创建了一个特殊的边界条件(并且您可能已经有了一个测试,该测试记录了当Foo
返回null
时yell
执行的操作)。
Pirate.yell
不负责保证Foo.bar
的任何特定返回值,因此它的单元测试不应该期望任何特定的返回values.You甚至应该特别注意更改测试以使用Foo.bar
的当前返回值以外的其他值。
https://stackoverflow.com/questions/3831400
复制相似问题