【发布时间】:2014-04-09 03:48:09
【问题描述】:
假设我有以下课程
public abstract class Foo{
public int bar(){
//implementation
}
public abstract int bar2();
}
和一个基类,以便更轻松地为此类编写装饰器
public class FooWrapper{
private final Foo delegate;
protected FooWrapper( Foo delegate ){
this.delegate = delegate;
}
@Override
public int bar(){
return delegate.bar()
}
@Override
public int bar2(){
return delegate.bar2();
}
}
FooWrapper 类允许您为 Foo 编写装饰器,您只需覆盖您需要的方法。
现在我想为FooWrapper 编写一个测试,检查所有方法是否默认委托。当然我可以写类似的东西
@Test
public void barShouldBeDelegated(){
Foo delegate = Mockito.mock( Foo.class );
FooWrapper wrapper = new FooWrapper( delegate );
wrapper.bar();
Mockito.verify( delegate ).bar();
}
但这需要我在每次将方法添加到Foo 时添加一个新的测试方法。我希望每次向Foo 添加一个方法时都会失败的测试,我忘记在FooWrapper 中覆盖和委托。
我试图使用允许我调用每个方法的反射,但我不知道如何检查该方法是否实际被委托。有关我正在玩弄的想法,请参阅以下 sn-p:
@Test
public void testAllMethodsAreDelegated() throws Exception{
Foo delegate = mock(Foo.class);
FooWrapper wrapper = new FooWrapper(delegate);
Class<?> clazz = wrapper.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] arguments = new Object[parameterTypes.length];
for (int j = 0; j < arguments.length; j++) {
arguments[j] = Mockito.mock(parameterTypes[j]);
}
method.invoke(wrapper, arguments);
// ?? how to verify whether the delegate is called
// Mockito.verify( delegate ).??? does not work
// as I cannot specify the method by name
}
}
}
任何想法是否可以编写这样的测试。请注意,我可以使用的唯一模拟框架是 Mockito。
【问题讨论】:
-
很好的描述和好主意:)
-
你能从接受的答案中得到一些有用的东西吗?它有一个非常致命的缺陷,它实际上并没有验证委托方法是否被调用(见下面的评论)。
-
@Krease 我使用了接受的答案,它似乎有效。当包装器不调用委托时测试失败。仅在包装器和委托中使用相同的方法(在它们相互扩展时总是如此)将使测试失败。所以我不确定我 100% 理解你的话
-
奇怪 - 我尝试了同样的事情并且能够以多种方式打破它.. (另外,从这里的例子
FooWrapper不扩展Foo,但包含一个 - 它们可以是不同的类层次结构)。我会进一步调查我的具体案例,也许还有其他原因导致我的测试无法正确...... -
...我错了,它确实有效——我对我的版本进行了一些调整,否定了它有效的原因。我会更新答案以澄清。
标签: java unit-testing decorator mockito