Я думаю, что вы неправильно используете аннотацию @InjectMocks
Имеет смысл, если у вас есть реальный класс (обычно тот, который вы хотите проверить), который имеет зависимости , которые инициализируются с помощью Внедрение в конструктор или в сеттер. С другой стороны,
BBServiceImpl
не имеет реальных зависимостей.
Теперь вы можете вручную создавать макеты для этих зависимостей, а затем создавать экземпляр тестируемого класса. или пусть mockito определит способ создания класса и «закачает» макеты для вас. Вы по-прежнему хотите создавать макеты с помощью аннотации @Mock
, поскольку вы хотите указать ожидания во время теста.
Вот пример того, как это должно выглядеть:
public interface BBService {
int process(String s); // simplified but still illustrates the concept
}
public class BBServiceImpl implements BBService {
//here is a dependency that should be mocked when we will test BBServiceImpl class
private SizeCalculator sizeCalculator;
// I use constructor injection here
public BBServiceImpl(SizeCalculator sizeCalculator) {
this.sizeCalculator = sizeCalculator;
}
public int process(String s) {
// here is a dependency invocation
return sizeCalculator.calculateSize(s);
}
}
Как видите, реализация имеет реальную зависимость, которую можно смоделировать во время теста.
Теперь эта зависимость выглядит следующим образом:
public interface SizeCalculator {
int calculateSize(String s);
}
public class SizeCalculatorImpl implements SizeCalculator {
public int calculateSize(String s) {
return s.length();
}
}
Хорошо, теперь давайте создадим тест за BBServiceImpl
. Мы не хотим создавать SizeCalculatorImpl
и предпочитаем предоставлять макет для него и указывать ожидание для сгенерированного прокси во время выполнения, созданного из интерфейса SizeCalcluator
:
@RunWith(MockitoJUnitRunner.class)
public class MockitoInjectMocksTest {
// I need a reference on my mock because I'll specify expectations during the tests
@Mock
private SizeCalculator sizeCalculator;
@InjectMocks
private BBServiceImpl underTest;
@Test
public void testInjectMocks() {
Mockito.when(sizeCalculator.calculateSize("hello")).thenReturn(5);
int actual = underTest.process("hello");
assertEquals(actual, 5);
}
}
Обратите внимание на строку
@InjectMocks
private BBServiceImpl underTest;
Mockito найдет конструктор и введет макет
Конечно, в этом случае мы можем сделать это вручную:
@RunWith(MockitoJunitRunner.class)
public class SampleManualTest {
@Mock
private SizeCalculator sizeCalc;
private BBServiceImpl underTest;
@Before
public void init() {
this.underTest = new BBServiceImpl(sizeCalc);
}
}
Но подумайте о случае, когда есть Есть много зависимостей в классе BBServiceImpl
, InjectMocks может быть более удобным в этом случае +, если используется инъекция сеттера, этот способ может сохранять явные вызовы сеттерам.