【问题标题】:Automatically delegate implementing methods自动委托实现方法
【发布时间】:2019-08-17 02:00:57
【问题描述】:

我可以自动将所有调用委托给共享同一接口的另一个实例的方法吗?

我有一个像这样的大课(我想测试):

class MyClassUnderTest implements SomeInterface {
  public void anImportantMethod() {
  }
  @Override
  public void fromTheInterface() {
  }
  @Override
  public void fromTheInterface2() {
  }
  private void utilFunc() {}
}

它实现了一个接口

interface SomeInterface {
  void fromTheInterface();
  void fromTheInterface2();
}

鉴于此,在单元测试期间,我想“隐藏”从具有不同实现的接口继承的方法。为此,我编写了一个实用程序类

class DebugSomeInterface implements SomeInterface {
  @Override public void fromTheInterface() { log.debug("1"); }
  @Override public void fromTheInterface2() { log.debug("2"); };
}

现在我需要将所有可能的调用“委托”给该实现。我通过派生自 MyClassUnderTest 我自己的类来手动完成此操作,并将所有调用委托给该类:

class MyClassUnderTest_Mock extends MyClassUnderTest {
    DebugSomeInterface delegated = new DebugSomeInterface();

  @Override public void fromTheInterface() {
    delegated.fromTheInterface();
  }
  @Override public void fromTheInterface2() { 
    delegated.fromTheInterface2();
  };

只是,我有很多实现SomeInterface 的类,而手动执行此操作既乏味又容易出错。

我想要一种(半)自动化的方式来创建 MyClassUnderTest_Mock 实例,就像使用 Mockito 的 mock(...) 一样。也许像

 MyClassUnderTest underTest = new MyClassUnderTest();
 DebugSomeInterface delegated = new DebugSomeInterface();
 MyClassUnderTest instance = mixin(underTest, SomeInterface.class, delegated);

这可能会创建一个“代理”instance,它将所有方法调用从 SomeInterface 委托给 delegated,其余的委托给 underTest

在核心 Java 中有一些代理对象机制,但我无法将它们全部结合在一起。

【问题讨论】:

  • 你可以 spy(new MyClassUnderTest()) 然后模拟出你想要提供行为的方法

标签: java unit-testing proxy mockito delegation


【解决方案1】:

你可以这样做:

public static <T, U extends T> U createProxy(U classUnderTest, Class<T> interfaceType, T debugImplementation)
        throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    U spy = Mockito.spy(classUnderTest);
    for (Method m : interfaceType.getMethods()) {
        Object[] params = new Object[m.getParameterTypes().length];
        for (int i = 0; i < params.length; i++) {
            params[i] = Mockito.any();
        }
        Mockito.when(m.invoke(spy, params)).thenAnswer(new Delegate(debugImplementation, m));
    }
    return spy;
}

public static class Delegate implements Answer {
    private final Object delegate;

    private final Method delegateMethod;

    public Delegate(Object delegate, Method delegateMethod) {
        this.delegate = delegate;
        this.delegateMethod = delegateMethod;
    }

    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return delegateMethod.invoke(delegate, invocation.getArguments());
    }
}

然后像这样使用它:

MyClassUnderTest underTest = new MyClassUnderTest();
DebugSomeInterface delegated = new DebugSomeInterface();
MyClassUnderTest instance = createProxy(underTest, SomeInterface.class, delegated);

这将按照您的意愿工作,但作为免责声明,我认为这是一个坏主意...必须监视被测对象并模拟被测对象的某些部分应该是一个危险信号...这是不好的做法,你只需要在代码复杂度高于最佳值并且你的类的一部分应该被分成其他类时做这样的事情。我从来没有遇到过这样的情况,重构我的逻辑并不是更好的解决方案......

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-13
    相关资源
    最近更新 更多