Автоматически делегировать методы реализации - PullRequest
0 голосов
/ 26 марта 2019

Могу ли я автоматически делегировать все вызовы методам другого экземпляра, которые используют один и тот же интерфейс?

У меня большой класс (я хочу проверить), например:

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

Реализует интерфейс

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

Учитывая, что во время unittest я хочу «скрыть» методы, унаследованные от интерфейса с различными реализациями. Для этого я написал служебный класс

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 экземпляров, как mock(...) с помощью Mockito. Может быть, что-то вроде

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

Возможно, это создаст «прокси» instance, который делегирует все вызовы методов от SomeInterface до delegated, а остальные underTest.

В ядре Java есть некоторый механизм с прокси-объектами, но я не могу собрать все это вместе.

1 Ответ

0 голосов
/ 29 марта 2019

Вы можете сделать что-то вроде этого:

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);

Это будет работать так, как вы хотите, но как заявление об отказе от ответственности, я думаю, что это плохая идея ... Необходимость шпионить за тестируемым объектом и вытаскивать куски тестируемого объекта должна быть красным флагом ... Это Это плохая практика, вам нужно делать такие вещи только тогда, когда сложность кода выше оптимальной и части вашего класса должны быть разделены на другие классы. Я никогда не сталкивался с такой ситуацией, когда рефакторинг моей логики не был лучшим решением ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...