Я дізнався про Mockito лише сьогодні. Я написав кілька простих тестів (з JUnit, див. Нижче), але я не можу зрозуміти, як я можу використовувати макетний об'єкт у керованих компонентах Spring. Які найкращі практики роботи з Spring. Як я повинен вводити глумливу залежність до моєї квасолі?
Ви можете пропустити це до повернення до мого запитання .
Перш за все те, що я дізнався. Це дуже хороша стаття Mocks Aren't Stubs, яка пояснює основи (Mock перевіряє перевірку поведінки, а не перевірку стану ). Тоді є хороший приклад тут Mockito, а тут Простіше глузування з mockito . У нас є пояснення , що фіктивні об'єкти Mockito є як насмішка і заглушки .
Тут 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 Integration Tests, створюючи Mock Objects, ми маємо рекомендацію змінити контекст Spring.
Я насправді не розумів останніх двох посилань ... Хтось може пояснити мені, яка проблема у Spring з Mockito? Що не так із цим рішенням?
@InjectMocks
private MyTestObject testObject
@Mock
private MyDependentObject mockedObject
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
https://stackoverflow.com/a/8742745/1137529
EDIT : Я насправді не був зрозумілим. Я наведу 3 приклади коду, щоб пояснити себе: Припустимо, у нас є компонент HelloWorld з методом printHello()
і компонент 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();
}
}
Нічого, що в попередньому прикладі ми повинні вручну інстанувати HelloFacadeImpl і призначити його HelloFacade, оскільки HelloFacade є інтерфейсом. В останньому прикладі ми можемо просто оголосити HelloFacadeImpl, і Mokito створить його для нас. Недоліком цього підходу є те, що зараз блок тестування є імпл-класом, а не інтерфейсом.
@InjectMocks
(порівняно недавно, хоча до цього повідомлення в блозі IIRC), тому існують обставини, коли може знадобитися переупорядкування визначень бобів. Я не впевнений, у чому, зрештою, питання.