验证是否已调用所有getter方法

Geo*_*his 8 java reflection junit unit-testing mockito

我有以下测试,我需要验证是否正在调用Person类的所有getter.到目前为止,我已经使用了mockito的verify()来确保调用每个getter.有没有办法通过反思来做到这一点?可能是这样的情况,新的getter被添加到Person类,但测试将错过.

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()???**
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jef*_*ica 9

一般来说,不要嘲笑被测试的课程.如果你的测试是针对一个人的,你就不应该看到Mockito.mock(Person.class)它,因为这是一个非常清楚的迹象,表明你正在测试模拟框架而不是被测系统.

相反,您可能想要创建一个spy(new Person()),它将使用真实构造函数创建一个真实的Person实现,然后将其数据复制到Mockito生成的代理.您可以MockingDetails.getInvocations()反复检查是否已调用每个getter.

// 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();
}
Run Code Online (Sandbox Code Playgroud)

可能有一种方式可以打电话verifyinvokeMockito生成的间谍,但这似乎非常脆弱,并且非常依赖于Mockito内部.

另外,测试bean风格的getter似乎是时间/精力的奇怪用法.通常侧重于测试可能会改变或破坏的实现.