Глубокая насмешка не работает как член @InjectMocks - PullRequest
0 голосов
/ 04 июня 2018

Аннотация @InjectMocks дает нам возможность заглушить / закрепить частного участника и повторно использовать тестовый пример.Вот концептуальный код, в котором проблема возникла, когда мы подделали Фальшивого Участника.

  public class TestBuilder{
      @Spy
      private StubComponent componentA = new StubComponent();
      @Mock
      private FakeComponent componentB;
      @InjectMocks
      private class TestTarget targetInstance = mock(TestTarget.class);

      public static Class TestTarget{
        private StubComponent componentA;
        private FakeComponent componentB;
        public ShimmedResultB testInvokation(String para){
            componentA.doCallRealMethod();
            ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
            ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
            return shouldNotBeNull;
        }
      }

      private TestBuilder(){
        MockitoAnnotations.initMocks(this);
        //Shim the real component A with partial stubbed
        doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());
        //Shim the fake component B
        //************The issue is here****************
        componentB = mock(FakeComponent.class);
        //*********************************************
        when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);

      }
      public TestTarget getTargetInstance(){
        return this.targetInstance;
      }

      public static TestTarget build(){
        return (new TestBuilder()).getTargetInstance();
      }

      public static main(String[] args){
        TestTarget testInstance = TestBuilder.build();
        ShimmedResultB result = testInstance.testInvokation("");
        assertThat(result, not(equalTo(null)));
      }
  }

Проблема в том, что мы высмеиваем Фальшивого componentB.Тогда someShimmedMethod вернет ноль.Похоже, что InjectMocks не может отнести mock() к приватному члену.

Вот несколько определений терминологии:

  1. StubComponent: тест проникнет в этот компоненткак частный участник.Тем не менее, есть какой-то метод, который может не пройти.Мы могли бы воспользоваться его публичным методом.Этот компонент может иметь меньшую область зависимостей, которые легко могут быть инициированы локальным ресурсом.

  2. FakeComponent: Этот компонент будет тестироваться где-то еще.Здесь мы можем построить только макетированный экземпляр и использовать все методы для цели теста.

  3. Заглушка: @Spy может помочь нам перехватить член-заглушку.Частный член не на 100% реален.Но некоторая часть с заглушкой может позволить тесту проникнуть в этот закрытый элемент.

  4. Shim: @Mock выдаст нам нулевой указатель до initMocks.Таким образом, мы можем начать проектировать возврат компонента Fake после initMocks.Это магия @InjectMocks.Тем не менее, это самая сложная часть, так как разработчик хотел бы инициировать каждую вещь и макет (FakeComponent.class) для componentB интуитивно.Это очистит весь отмытый дизайн и сделает ваше утверждение неудачным.

========================================================================

Спасибо Maciej'sОтветьте и извините за опечатку, когда я переведу структуру моего теста.И позвольте мне поднять проблему с более ясным описанием к ответу Мачей.

  public class TestBuilder{
      @Spy
      private StubComponent componentA = new StubComponent();
      @Mock
      private FakeComponent componentB;
      @InjectMocks
      private TestTarget targetInstance = mock(TestTarget.class);

      public static Class TestTarget{
        private StubComponent componentA;
        private FakeComponent componentB;
        public ShimmedResultB testInvokation(String para){
            componentA.doCallRealMethod();
            ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
            ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
            return shouldNotBeNull;
        }

        public TestTarget(){
            //The FakeComponent has some specific remote resource
            //And could not be initialized here
            componentB = new FakeComponent();
            //We will use mock server to test this FakeComponent else where
        }
      }

      private TestBuilder(){
        //Hook the testing Function for trigger the step in
        doCallRealMethod().when(this.targetInstance).testInvokation(anyString());
        //Inject Stubbed and Faked Private Member for testing
        MockitoAnnotations.initMocks(this);
        //Shim the real component A with partial stubbed
        doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());

        //************The issue is here****************
        componentB = mock(FakeComponent.class);
        //*********************************************
        //Shim the leveraged method of fake componentB
        when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);
      }

      public TestTarget getTargetInstance(){
        return this.targetInstance;
      }

      public static TestTarget build(){
        return (new TestBuilder()).getTargetInstance();
      }

      public static main(String[] args){
        TestTarget testInstance = TestBuilder.build();
        //The doRealCall hook will trigger the testing
        ShimmedResultB result = testInstance.testInvokation("");
        assertThat(result, not(equalTo(null)));
      }
  }

Во второй концептуальный код добавлено что-то:

  1. Компонент B - это область, которую мыне хочу вмешиваться. Однако TestTarget имеет инициацию с componentB в своем конструкторе.Это довольно часто, когда у нас есть утилита, связанная с удаленным источником.Мы используем для тестирования componentB независимо с имитацией сервера или другой техники.Следовательно, мы можем использовать только mock (TestTarget.class).

  2. Так как мы высмеивали TestTarget.Я пропустил одну вещь: нам нужно использовать doCallRealMethod (). When (targetInstance) для запуска testInvokation ().И это ограничивает нулевое объявление targetInstance.Нам нужно использовать mock () и перехватить doCallRealMethod.

Таким образом, в результате нам нужно оставить @Mock равным null без mock (), чтобы @InjectMocks мог обрабатывать shim.Мы обнаружили, что это сложно, когда мы используем @ InjectMocks.

1 Ответ

0 голосов
/ 04 июня 2018

Проблема связана с определением @InjectMocks:

@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);

Тестируемый класс никогда не должен быть ложным (также почему ключевое слово class).

Попробуйте использовать:

@InjectMocks
private TestTarget targetInstance = new TestTarget();

или просто:

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