![](/img/trans.png)
[英]How do I get the test class instance JUnit is running test cases on from inside the ClassRunner?
[英]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;
- 所有私有属性(使用getters / setters )
- 一个公开的无参数构造函数
- 实现
Serializable
。
换句话说,Bean只是一种数据结构。 它没有任何行为,也没有想要防止发生的意外后果。 换句话说,你不应该嘲笑BeanInfo
可言 。
但是,您确实要确保您的类对BeanInfo对象执行正确的操作。 您想在生产代码和测试中都获得真实的 BeanInfo
对象,因为它是一个数据结构。 因此,您真正需要的是一种在测试方法中访问这些实际BeanInfo
对象的方法。
注意:您将无法避免在这里使用真正的Introspector
,因为您的应用程序需要它提供的数据。
这是解决问题的方法:
重构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; } }
可以通过添加构造函数参数将此行为注入ClientViewer
。
private final BeanInfoProvider provider; public ClientViewer(..., BeanInfoProvider provider) { // snip this.provider = provider; }
更改使用BeanInfo
的方法以使用此BeanInfoProvider
protected void sub(Object obj) { try { BeanInfo beanInfo = provider.getBeanInfo(obj); // snip
实现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); } } }
注入到您的测试中
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.