Насмешка над классом пружины с помощью конструктора - PullRequest
0 голосов
/ 25 марта 2020

У меня есть следующий класс:

@Service
public class SomeClass extends BaseClass {
  private final SomeService someService;

  public SomeClass(SomeService someService) {
    this.someService = someService;
  }

  public List<String> methodToTest(SomeDataClass data) {
    if (!checkData(data)) { // checkData is defined in BaseClass and does lots of unimportant stuff
      throw BadDataException();
    }

    return someService.getData();
  }
}

Теперь я хочу создать тестовые сценарии для SomeClass с использованием Mockito.

  1. Проверить, что вызывается checkData ().
  2. Проверьте, что вызывается someService.getData ().

Используя Mockito, я справился с контрольным примером 1 с помощью:

@Test(expected = BadDataException.class)
public void methodToTest_checkDataCalled() {
  SomeClass mock = mock(SomeClass.class);
  when(mock.methodToTest(any()).thenCallRealMethod();
  when(mock.checkData(any()).thenReturn(false);

  mock.methodToTest(new SomeData());
  verify(mock).checkData(any());
}

Однако у меня возникли проблемы при создании контрольного примера № 2 , Я могу либо создать SomeClass вручную с помощью SomeClass someClass = new SomeClass(mockSomeService), но затем мне нужно создать фиктивные данные для расширенного запроса checkData (), который я на самом деле не хочу тестировать в этом тестовом примере, поскольку он уже покрыт другим тестом и требует много ненужных насмешек, или я могу издеваться над SomeClass, как в тестовом примере # 1, но тогда someService всегда пуст, независимо от того, что я пытаюсь.

Я пробовал варианты @InjectMocks, @Mock и тому подобное, но я не смог создать работоспособное решение.

Вещи, которые я пробовал:

@Mock
private SomeService someService;

@Before
public void setUp() {
  someService = mock(SomeService.class);
  when(someService.getData()).thenReturn(Collections.singletonList("Mock"));
}

@Test
public void methodToTest_someServiceCalled1() {
  SomeClass mock = mock(SomeClass.class);
  when(mock.methodToTest(any()).thenCallRealMethod();
  when(mock.checkData(any()).thenReturn(true);

  List<String> result = mock.methodToTest(new SomeData()); // NullPointerException at someService.getData() call
  verify(someService).getData();
  assertEquals("Mock", result.get(0));
}

@Test
public void methodToTest_someServiceCalled2() {
  SomeClass someClass = new SomeClass(someService);
  List<String> result = someClass.methodToTest(new SomeData()); // Fails at checkData() call
  verify(someService).getData();
  assertEquals("Mock", result.get(0));
}

Как я могу вызвать ложный вызов для someService, в то же время высмеивая вызов родителю классы checkData ()? Возможно ли это без рефакторинга SomeClass?

1 Ответ

1 голос
/ 25 марта 2020

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

Вот рабочий пример.

@Mock
private SomeService someService;

@InjectMocks
private SomeClass classUnderTest;

@Before
public void setUp() {
    Mockito.when(someService.getData()).thenReturn(Collections.singletonList("Mock"));
}

@Test
public void methodToTest_someServiceCalled1() {

  SomeClass spy = Mockito.spy(classUnderTest);
  Mockito.when(spy.checkData(Mockito.any())).thenReturn(true);

  List<String> result = spy.methodToTest(new SomeData());
  Mockito.verify(someService).getData();
  assertEquals("Mock", result.get(0));
}

Я не уверен, что вы 2-й тест, на самом деле, я бы назвал оригинал checkData метод. Как вы упомянули, это то, что вы хотите избежать, решение должно быть похоже на 1-й тест.

...