繁体   English   中英

如何从JUnit测试中的模拟对象获取typeName()?

[英]How do I get typeName() from a mock object in a JUnit test?

这是我不得不模拟的最奇怪的方法之一。 我需要以某种方式使我的单元测试与以下代码一致:

protected void sub(Object obj) {
    try {
        BeanInfo beanInfo = getBeanInfo(obj);
        for (PropertyDescriptor pb : beanInfo.getPropertyDescriptors()) {
            String fieldType = pd.getPropertyType.getTypeName();
            System.out.println(fieldType);
        }
    } catch (InvocationTargetException | IllegalAccessException e) {
        e.printStackTrace();
    }
}

它看起来像是一个简单的单元测试(我将getBeanInfo()移到了一个单独的方法,所以我可以模拟它而不用跳过Introspector)。 但是,每当我到达getTypeName()时,它将始终抛出InvocationTargetException。 有没有办法模拟PropertyDescriptor的属性类型? 我在这里找到了关于stackoverflow的解决方案,但并没有太大帮助。

带有Mockito.when()和通用类型推断的奇怪的通用边缘情况

这是我如何模拟BenInfo对象的代码:

@Test
public void testSub() {
    ClientViewer cv = mock(ClientViewer.class); // The class that I'm testing.
    when(cv.getBeanInfo(mockValue)).thenReturn(mockBeanInfo);

    // Rest of the test.
}

模拟值对象只是一个通用对象。 mockBeanInfo对象是很容易解释的。 此代码可以正常工作。 问题是嘲笑PropertyDescriptor名称。

这是getBeanInfo():

protected BeanInfo getBeanInfo(Object obj) {
    BeanInfo beanInfo = null;

    try {
        Class cls = obj.getClas();
        beanInfo = Introspector.getBeanInfo(cls);
    } catch (IntrospectionException e) {
        e.printStackTrace();
    }

    return beanInfo;
}

最后是mockBeanInfo:

@Mock private java.beans.BeanInfo mockBeanInfo;

让我们谈谈什么是Java Bean

  1. 所有私有属性(使用getters / setters
  2. 一个公开的无参数构造函数
  3. 实现Serializable

换句话说,Bean只是一种数据结构。 它没有任何行为,也没有想要防止发生的意外后果。 换句话说,你不应该嘲笑BeanInfo 可言

但是,您确实要确保您的类对BeanInfo对象执行正确的操作。 您想在生产代码和测试获得真实的 BeanInfo对象,因为它是一个数据结构。 因此,您真正需要的是一种在测试方法中访问这些实际BeanInfo对象的方法。

注意:您将无法避免在这里使用真正的Introspector ,因为您的应用程序需要它提供的数据。

这是解决问题的方法:

  1. 重构getBeanInfo()行为以使用单独的类BeanInfoProvider

     public class SimpleBeanInfoProvider implements BeanInfoProvider { public BeanInfo getBeanInfo(Object obj) { BeanInfo beanInfo = null; try { Class cls = obj.getClass(); beanInfo = Introspector.getBeanInfo(cls); } catch (IntrospectionException e) { e.printStackTrace(); } return beanInfo; } } 
  2. 可以通过添加构造函数参数将此行为注入ClientViewer

     private final BeanInfoProvider provider; public ClientViewer(..., BeanInfoProvider provider) { // snip this.provider = provider; } 
  3. 更改使用BeanInfo的方法以使用此BeanInfoProvider

     protected void sub(Object obj) { try { BeanInfo beanInfo = provider.getBeanInfo(obj); // snip 
  4. 实现BeanInfoProvider的实现,该实现生成间谍程序并允许您访问它们。 注意:您需要缓存BeanInfo间谍,以确保在ClientViewer和测试方法中获得相同的间谍。

     public class SpyBeanInfoProvider implements BeanInfoProvider { private final BeanInfoProvider delegate; private final Map<Class<?>, BeanInfo> spyMap = new HashMap<>(); public SpyBeanInfoProvider(BeanInfoProvider delegate) { this.delegate = delegate; } @Override public BeanInfo getBeanInfo(Object obj) { Class<?> klass = obj.getClass(); if(!spyMap.containsKey(klass)) { BeanInfo info = spy(delegate.getBeanInfo(obj)); spyMap.put(klass, info); return info; } else { return spyMap.get(obj); } } } 
  5. 注入到您的测试中

     private BeanInfoProvider makeBeanInfoProvider() { return new SpyBeanInfoProvider(new IntrospectorBeanInfoProvider()); } @Test public void testSub() { BeanInfoProvider provider = makeBeanInfoProvider(); ClientViewer viewer = new ClientViewer(makeBeanInfoProvider()); viewer.sub(obj); BeanInfo spy = provider.getBeanInfo(obj); // Now do your test verify(spy).getPropertyDescriptors(); // etc. } 

这将允许您访问所生成的BeanInfo对象-因为它们是作为部分模拟实现的真实数据结构,并且您将不再获得这些InvocationTargetException

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM