Я дізнався про 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), тому існують обставини, коли може знадобитися переупорядкування визначень бобів. Я не впевнений, у чому, зрештою, питання.