验证是否调用了所有 getter 方法
我有以下测试,我需要验证是否调用了 Person 类的所有 getter.到目前为止,我已经使用了 mockito 的 verify() 来确保调用每个 getter.有没有办法通过反思来做到这一点?可能会在 Person 类中添加一个新的 getter,但测试会错过它.
I have the following test where I need to verify that all getters of the Person class are being called. So far I have used mockito's verify() to make sure that each getter is called. Is there a way to do that by reflection? It can be the case that a new getter is added to the Person class but the test will miss that.
public class GetterTest {
class Person{
private String firstname;
private String lastname;
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
}
@Test
public void testAllGettersCalled() throws IntrospectionException{
Person personMock = mock(Person.class);
personMock.getFirstname();
personMock.getLastname();
for(PropertyDescriptor property : Introspector.getBeanInfo(Person.class).getPropertyDescriptors()) {
verify(personMock, atLeast(1)).getFirstname();
//**How to verify against any getter method and not just getFirstName()???**
}
}
}
推荐答案
一般情况下,不要模拟被测类.如果您的测试是针对 Person 的,那么您永远不会在其中看到 Mockito.mock(Person.class)
,因为这是一个非常明显的迹象,表明您正在测试模拟框架而不是系统- 正在测试中.
Generally, don't mock the class under test. If your test is for a Person, you shouldn't ever see Mockito.mock(Person.class)
in it, as that's a pretty clear sign that you're testing the mocking framework instead of the system-under-test.
相反,您可能想要创建一个 spy(new Person())
,它将使用真正的构造函数创建一个真正的 Person 实现,然后将其数据复制到 Mockito 生成的代理.您可以使用 MockingDetails.getInvocations()
反射性地检查是否调用了每个 getter.
Instead, you may want to create a spy(new Person())
, which will create a real Person implementation using a real constructor and then copy its data to a Mockito-generated proxy. You can use MockingDetails.getInvocations()
to reflectively check that every getter was called.
// This code is untested, but should get the point across. Edits welcome.
// 2016-01-20: Integrated feedback from Georgios Stathis. Thanks Georgios!
@Test
public void callAllGetters() throws Exception {
Person personSpy = spy(new Person());
personSpy.getFirstname();
personSpy.getLastname();
assertAllGettersCalled(personSpy, Person.class);
}
private static void assertAllGettersCalled(Object spy, Class<?> clazz) {
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
Set<Method> setOfDescriptors = beanInfo.getPropertyDescriptors()
.stream()
.map(PropertyDescriptor::getReadMethod)
.filter(p -> !p.getName().contains("getClass"))
.collect(Collectors.toSet());
MockingDetails details = Mockito.mockingDetails(spy);
Set<Method> setOfTestedMethods = details.getInvocations()
.stream()
.map(InvocationOnMock::getMethod)
.collect(Collectors.toSet());
setOfDescriptors.removeAll(setOfTestedMethods);
// The only remaining descriptors are untested.
assertThat(setOfDescriptors).isEmpty();
}
可能有一种方法可以在 Mockito 生成的间谍上调用 verify
和 invoke
,但这似乎非常脆弱,并且非常依赖于 Mockito 内部结构.
There might be a way to call verify
and invoke
on the Mockito-generated spy, but that seems very fragile, and very dependent on Mockito internals.
顺便说一句,测试 bean 样式的 getter 似乎是对时间/精力的一种奇怪使用.一般来说,重点是测试可能会更改或中断的实现.
As an aside, testing bean-style getters seems like an odd use of time/effort. In general focus on testing implementations that are likely to change or break.
相关文章