Я начал узнавать о Мокито только сегодня. Я написал несколько простых тестов (с JUnit, см. Ниже), но я не могу понять, как я могу использовать mock-объект внутри Spring управляет beans. Что лучше всего подходит для работы с Spring. Как я должен вводить в заблуждение зависимость от моего bean?
Вы можете пропустить это до назад к моему вопросу.
Прежде всего, что я узнал. Это очень хорошая статья Mocks Are not Stubs, которая объясняет основы (Mock проверяет проверку проверки поведения). Тогда здесь есть хороший пример Mockito Здесь Легче насмешливо с mockito у нас есть объяснение, что Mockito mock objects являются и макетными, и заглушками.
Здесь Mockito и здесь Matchers вы можете найти больше примеров.
Этот тест
@Test
public void testReal(){
List<String> mockedList = mock(List.class);
//stubbing
//when(mockedList.get(0)).thenReturn("first");
mockedList.get(anyInt());
OngoingStubbing<String> stub= when(null);
stub.thenReturn("first");
//String res = mockedList.get(0);
//System.out.println(res);
//you can also verify using argument matcher
//verify(mockedList).get(anyInt());
verify(mockedList);
mockedList.get(anyInt());
}
отлично работает.
Вернуться к моему вопросу. Здесь Инъекция Mockito издевается над Spring bean, кто-то пытается использовать Springs ReflectionTestUtils.setField()
, но здесь Spring Интеграционные тесты, создание Mock Objects, мы рекомендуем изменить контекст Spring.
Я не очень понял последние две ссылки... Может кто-нибудь объяснить мне, что проблема с Spring с Mockito? Что не так с этим решением?
@InjectMocks
private MyTestObject testObject
@Mock
private MyDependentObject mockedObject
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
РЕДАКТИРОВАТЬ: я был не совсем понятен. Я приведу 3 примера кода, чтобы прояснить себя:
Предположим, мы имеем bean HelloWorld с методом printHello()
и bean HelloFacade с методом sayHello
, который переадресовывает метод HelloWorld printHello()
.
В первом примере используется контекст Spring и без специального бегуна, используя ReflectionTestUtils для инъекции зависимостей (DI):
public class Hello1Test {
private ApplicationContext ctx;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.ctx = new ClassPathXmlApplicationContext("META-INF/spring/ServicesImplContext.xml");
}
@Test
public void testHelloFacade() {
HelloFacade obj = (HelloFacade) ctx.getBean(HelloFacadeImpl.class);
HelloWorld mock = mock(HelloWorld.class);
doNothing().when(mock).printHello();
ReflectionTestUtils.setField(obj, "hello", mock);
obj.sayHello();
verify(mock, times(1)).printHello();
}
}
Как @Noam указал, что существует способ запустить его с явным вызовом MockitoAnnotations.initMocks(this);
. Я также остановлю использование контекста Spring в этом примере.
@RunWith(MockitoJUnitRunner.class)
public class Hello1aTest {
@InjectMocks
private HelloFacade obj = new HelloFacadeImpl();
@Mock
private HelloWorld mock;
@Test
public void testHelloFacade() {
doNothing().when(mock).printHello();
obj.sayHello();
}
}
Другой способ сделать это
public class Hello1aTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@InjectMocks
private HelloFacadeImpl obj;
@Mock
private HelloWorld mock;
@Test
public void testHelloFacade() {
doNothing().when(mock).printHello();
obj.sayHello();
}
}
Noth, что в предыдущем примере нам нужно вручную установить HelloFacadeImpl и назначить его HelloFacade, beacuse HelloFacade - это интерфейс. В последнем примере мы можем просто объявить HelloFacadeImpl, и Mokito создаст его для нас. Недостатком этого подхода является то, что теперь под единым тестом подразумевается класс impl, а не интерфейс.