gpt4 book ai didi

java - 检查单元测试是否委托(delegate)了所有方法

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:13:32 24 4
gpt4 key购买 nike

假设我有以下类(class)

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 编写一个测试,检查所有方法是否默认委托(delegate)。当然我可以写类似的东西

@Test
public void barShouldBeDelegated(){
Foo delegate = Mockito.mock( Foo.class );
FooWrapper wrapper = new FooWrapper( delegate );
wrapper.bar();
Mockito.verify( delegate ).bar();
}

但这需要我在每次向Foo 添加方法时添加一个新的测试方法。我希望每次我向 Foo 添加一个方法时都会失败,我忘记在 FooWrapper 中覆盖和委托(delegate)。

我试图使用允许我调用每个方法的反射,但我不知道如何检查该方法是否实际被委托(delegate)。请参阅以下片段了解我正在玩弄的想法:

  @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。

最佳答案

这段代码似乎可以解决问题。如果我向 Foo 添加方法但不将其包含在 FooWrapper 中,则测试失败。

    FooWrapper wrapper = new FooWrapper(delegate);
Foo delegate = Mockito.mock(Foo.class);

// For each method in the Foo class...
for (Method fooMethod : Foo.class.getDeclaredMethods()) {
boolean methodCalled = false;

// Find matching method in wrapper class and call it
for (Method wrapperMethod : FooWrapper.class.getDeclaredMethods()) {
if (fooMethod.getName().equals(wrapperMethod.getName())) {

// Get parameters for method
Class<?>[] parameterTypes = wrapperMethod.getParameterTypes();
Object[] arguments = new Object[parameterTypes.length];
for (int j = 0; j < arguments.length; j++) {
arguments[j] = Mockito.mock(parameterTypes[j]);
}

// Invoke wrapper method
wrapperMethod.invoke(wrapper, arguments);

// Ensure method was called on delegate exactly once with the correct arguments
fooMethod.invoke(Mockito.verify(delegate, Mockito.times(1)), arguments);

// Set flag to indicate that this foo method is wrapped properly.
methodCalled = true;
}
}

assertTrue("Foo method '" + fooMethod.getName() + "' has not been wrapped correctly in Foo wrapper", methodCalled);
}

您的代码中缺少的关键行是

fooMethod.invoke(Mockito.verify(delegate, Mockito.times(1)), arguments);

它可能看起来有点奇怪,但是这是有效的,因为它以 Mockito 期望的相同顺序调用事物:首先调用 Mockito.verify(delegate)(在内部启动 Mockito 验证),然后调用该方法。类似的非反射调用看起来像 Mockito.verify(delegate).foo()。使用这个“为什么”来帮助使代码适应不同的用例,而不会破坏测试进行验证的方式。

请注意,我会在每个迭代 getDeclaredMethods() 结果的循环的开头添加一个检查。此方法返回所有方法,无论它们是公共(public)的、私有(private)的、 protected 等。尝试访问不可访问的方法会引发异常。您可以使用 Method.isAccessible() 来检查这一点。

关于java - 检查单元测试是否委托(delegate)了所有方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22225663/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com