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



我有以下测试,我需要验证是否调用了 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()???**
        }
    }
}

一般来说,不要嘲笑被测试的类。如果你的测试是针对一个人的,你不应该在其中看到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();
}

可能有一种方法可以调用verifyinvoke Mockito生成的间谍,但这似乎非常脆弱,并且非常依赖于Mockito的内部结构。

顺便说一句,测试豆式的getter似乎是一种奇怪的时间/精力使用。通常专注于测试可能更改或中断的实现。

我可以为您的问题想到两种解决方案:

  1. 以编程方式生成生成器代码,因此无需运行测试。Java 代码由程序生成,从不由用户编辑。改为测试生成器。使用文本模板并从序列化域模型或直接从 Java 编译类构建定义(您需要一个依赖于 Bean 的单独模块)

  2. 针对代理库编写测试。问题是常规代理只能实现接口,而不能实现常规类,并且拥有 Javabeans 接口非常麻烦。如果你选择这条路线,我会选择Javassist。我编写了一个可运行的示例并将其放在GitHub上。测试用例使用代理工厂来实例化 bean(而不是使用 new

public class CountingCallsProxyFactory {
    public <T> T proxy(Class<T> classToProxy) {
        ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(classToProxy);
        Class clazz = factory.createClass();
        T instance =  (T) clazz.newInstance();
        ProxyObject proxy = (ProxyObject) instance;
        MethodCallCounter handler = new MethodCallCounter();
        proxy.setHandler(handler);
        return instance;
    }
    public void verifyAllGettersCalled(Object bean) {
        // Query the counter against the properties in the bean
    }
}

计数器保存在班级MethodCallCounter

相关内容

  • 没有找到相关文章

最新更新