2013-06-30 2 views
6

Предположим, у меня есть аннотация проверки на мой метод интерфейса для проверки входных аргументов и возвращаемого значения. Возможно ли на данный момент (V 1.9.5) сказать Mockito, чтобы вызвать этот валидатор во время процесса вызова?Можно ли использовать перехватчик для всех ответов при использовании Mockito?

Фон будет препятствовать разработчикам писать нереалистичные тесты, издеваясь над этим интерфейсом таким образом, который нарушает указанный валидатор.

Так что я хотел бы, чтобы зарегистрировать что-то вроде

class MyAnswerInterceptor<T> implements AnswerInterceptor<T> { 
    @Override 
    public Answer<T> intercept(final Answer<T> answer) { 
     return new Answer<T>() { 
      @Override 
      public T answer(InvocationOnMock invocation) throws Throwable { 
       validateArguments(invocation); 
       T result = answer.answer(invocation); 
       validateReturnValue(result); 
       return result; 
      } 
     } 
    } 
} 

называться по каждому ответу данного издеваться. Возможно ли это вообще? Я просмотрел код, также, чтобы проверить, могу ли я в какой-то момент взломать (даже используя отражение или что-то подобное), но, похоже, из-за запутанности создания экземпляра и логики едва ли можно достичь того, что я хочу (т. такие вещи, как MockHandler mockHandler = new MockHandlerFactory().create(settings); делает невозможным зацепить и положить вещи на заказ сверху без исправлений и развернув все это ...)

Любое понимание будет высоко оценен :-)

+0

Нашел одно решение, которое работает, а именно написать мой метод 'when (T methodCall)', внутри которого я делегирую 'Mockito.when', а затем завершаю OngoingStubbing в прокси-сервер Javassist и улавливаю все' thenBlubb (..) 'методы, переносящие соответствующий ответ в мой перехватчик и возвращающий прокси-сервер OngoingStubbing. Во всяком случае, это, конечно, не самый аккуратный способ, поэтому, если кто-то знает более красивый способ, я все еще открыт для предложений ;-) (в частности, он сосет обрабатывать все методы 'thenBlubb (..)', и он потребует дальнейшего внимание на каждое обновление ...) – pete83

+0

Кроме того, ваше решение не будет работать для таких методов, как методы void, где вам нужен синтаксис doXxx/when вместо синтаксиса when/thenXxx. Если вы не создадите собственные версии каждого из методов doXxx. –

+0

Привет! Вы хотите смешивать в простые модульные тесты какую-то очень сложную логику. Почему бы просто не протестировать сам валидатор отдельно от логики того, где он используется, и протестировать его вообще в тесте интеграции? –

ответ

2

Вы можете достичь этого путем создания изготовленный под заказ MockMaker.

MockMaker является точкой расширения, что позволяет использовать пользовательские динамические прокси и избегать использования по умолчанию CGLIB/ASM/objenesis реализация

Наши делегаты обычай реализации все сложный материал по умолчанию MockMaker: CglibMockMaker. Он «украшает» только метод createMock, зарегистрировавшись на параметре settings a InvocationListener. Этот слушатель будет уведомлен, когда были сделаны invocation, позволяющие использовать для вызова validateArguments и validateReturnValue.

import org.mockito.internal.creation.CglibMockMaker; 
import org.mockito.invocation.Invocation; 
import org.mockito.invocation.MockHandler; 
import org.mockito.listeners.InvocationListener; 
import org.mockito.listeners.MethodInvocationReport; 
import org.mockito.mock.MockCreationSettings; 
import org.mockito.plugins.MockMaker; 

public class ValidationMockMaker implements MockMaker { 
    private final MockMaker delegate = new CglibMockMaker(); 

    public ValidationMockMaker() { 
    } 
    @Override 
    public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) { 
     settings.getInvocationListeners().add(new InvocationListener() { 

      @Override 
      public void reportInvocation(MethodInvocationReport methodInvocationReport) { 
       Invocation invocation = (Invocation) methodInvocationReport.getInvocation(); 
       validateArguments(invocation.getArguments()); 
       validateReturnValue(methodInvocationReport.getReturnedValue()); 
      } 
     }); 
     return delegate.createMock(settings, handler); 
    } 

    @Override 
    public MockHandler getHandler(Object mock) { 
     return delegate.getHandler(mock); 
    } 

    @Override 
    public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) { 
     delegate.resetMock(mock, newHandler, settings); 
    } 

    protected void validateArguments(Object... arguments) { 
//  Arrays.stream(arguments).forEach(Objects::requireNonNull); 
    } 

    private void validateReturnValue(Object result) { 
//  Objects.requireNonNull(result); 
    } 
} 

И последнее, но не в последнюю очередь, мы должны сказать Mockito использовать нашу реализацию. Это возможно путем добавления файла

mockito-extensions/org.mockito.plugins.MockMaker 

, содержащий наше имя класса MockMaker:

ValidationMockMaker 

См Using the extension point раздел в Javadoc.

+0

Удивительно, что выглядит точно как вещь, в которой я нуждаюсь, большое спасибо !!! Я попробую этот подход как можно скорее :-) – pete83

Смежные вопросы