我有一个简单的类Foo
要模拟:
public class Foo {
private String name;
public Foo() {
}
public Foo(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
在我的单元测试代码中,我使用Mockito来模拟它。
Foo mockedFoo = Mockito.mock(Foo.class);
mockedFoo.setName("test");
// name is null
String name = mockedFoo.getName();
我在模拟对象中设置了name
,但当我调用getter获取名称时,它会返回null。
这是Mockito特有的问题,还是被嘲笑对象不能设置值的约定?为什么?被嘲笑的物体下面发生了什么?
是的,Foo
的实际代码无关紧要,因为你在嘲笑它……Mockito不知道setName
和getName
之间有关系。它不认为它应该将参数存储到setName
,并在调用getName
时返回。。。它可以做到这一点,但据我所知,它还没有做到。Mockito提供的mock只允许您指定对其调用方法时会发生什么,并检查稍后调用了什么。您可以模拟对getName()
的调用,并指定它应该返回什么,而不是调用setName
。。。
或者你可以直接使用Foo
而不是嘲笑它。不要认为你必须在测试中嘲笑所有。在使用真实类时,只需模拟(或伪造)一些尴尬的事情,例如,因为它使用了文件系统或网络。
默认情况下,mockito在模拟对象中的任何方法上都没有行为。
你应该这样做:
Foo mockedFoo = Mockito.mock(Foo.class);
when(mockedFoo.getName()).thenReturn("someName");
String name = mockedFoo.getName();
编辑:正如Jon Skeet所提到的,你不应该嘲笑那些可以正常测试的东西。
我认为,通过引用源代码Mockito source ,更好地理解Mockito对参数类做了什么,以及它返回了什么样的对象
一般的理解是,模拟对象是一个伪对象(与提供给mock()
方法的参数类型相同),没有真正的方法实现。所以基本上,在现实生活中,方法调用模拟对象不会发生任何事情——这正是创建模拟对象的目的(我们不希望调用真正的方法),不是吗?
我们模拟DAO层、LDAP层或其他服务依赖关系,因为我们不想调用对实际DB或服务的调用如果我们想要真正的调用发生,我们就不会创建模拟对象
理解在调用mockedFoo.setName("test");
或mockedFoo.getName();
之后发生了真实的事情是不正确的——在对模拟对象调用方法之后什么都不会发生,这就是它正在实现的模拟对象的目的。
要解决您知道代码中是否使用指定值调用了setName()方法的问题,请使用Mockito验证方法。
例如:
verify(mockedFoo, times(1)).setName("test");
将验证具有String参数"test"的mockedFoo.setName()方法在测试中的代码中是否只调用过一次。
您需要在模拟对象上调用真正的方法。使用@Spy
在某种程度上使用这种方法。我为EasyMock写过文章,但有了Mockito,它也可以同样使用。
String nameMock = createNiceMock(String.class);
Foo MockedFoo = new Foo();
Foo.setName(nameMock);
EasyMock.expect(Foo.getName()).andReturn(nameMock);