Mockito framework: создания заглушек для Unit тестов
Назначение фреймворка
Фреймворк Mockito предназначен для создание заглушек, которые можно использовать при написании Unit тестов вместо реальных классов или интерфейсов.Страница фреймворка: http://code.google.com/p/mockito/
Наиболее интересными мне показались следующие возможности фреймворка:
Библиотеки требуемые для работы примеров
Проект с примерами находится тут:https://github.com/nixx78/mockito-usage-samples
Примеры использования Mockito
Все примеры находятся в классе MockitoUsageSamples, в том же пакете находятся классы для которых создаются заглушки.Самый простой пример
Самый простой пример использования Mockito, мы создаем mock объект для интерефейса, вызываем у него методы, потом проверяем, действительно ли данные методы вызывались. При этом, мы можем проверить, параметры с которыми вызывались методы.
@Test
public void methodCallCheckSample() {
// create mock for interface
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// call methods
mockedObject.setStringValue("value1");
mockedObject.actionMethod();
// verify, that methods are called, please note that we check
// also parameter value
verify(mockedObject).setStringValue("value1");
verify(mockedObject).actionMethod();
// in this point we expect exception, because method "getStringValue" not called
//verify(mockedObject).getStringValue();
}
Чуть более сложный пример, добавим заглушки методов
Пример, в котором мы рассматриваем как мы можем сделать стабы для методов, в стабах мы указываем, какое значение мы ожидаем от метода при его вызове с определенными параметрами. Показаны различные подходы, как можно задавать условия,при создании заглушек для методов.
@Test
public void stubUsageSample() throws Exception{
// create mocked object
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// describe expected behavior for our interface
when(mockedObject.getStringValue()).thenReturn("expectedValue");
// we can define for one method different return values depending from input value
when(mockedObject.processMethod("input1")).thenReturn("value1");
when(mockedObject.processMethod("input2")).thenReturn("value2");
when(mockedObject.processMethod("input3")).thenThrow(new Exception("exception during method 'processMethod' call"));
// also we can define expected value using another approach: doReturn
doReturn("value4").when(mockedObject).processMethod("input4");
doThrow(new Exception()).when(mockedObject).processMethod("method with exception parameter");
// assert expected values, that method returns
assertEquals("value1", mockedObject.processMethod("input1"));
assertEquals("value2", mockedObject.processMethod("input2"));
try {
mockedObject.processMethod("input3");
} catch (Exception ex) {
// we expect exception there
System.err.println(ex);
}
// for non mocked input value we expect null
assertNull(mockedObject.processMethod("not mocked value"));
assertEquals("getString value", "expectedValue", mockedObject.getStringValue());
}
Сложная заглушка для метода - используем интерфейс Answer
Пример показывает пример реализации стабов для методов используя интерфейс Answer, данный подход позволяет реализовать заглушки методов со сложным поведением. Примером такого поведения может быть ситуация, когда ответ возвращаемый методом зависит не только от передаваемого параметра но и требует более сложной логики при его создании. @Test
public void smartStubUsageSample() throws Exception {
// create mock object
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// create mocked for method using call back
when(mockedObject.processMethod(anyString())).thenAnswer(new Answer() {
public String answer(InvocationOnMock invocation) {
// we can take method arguments as array of objects
Object[] args = invocation.getArguments();
return "called with arguments: " + args[0];
}
});
// calling method 'processMethod' we expect, that method 'answer' is called in mockedObject
String returnValue = mockedObject.processMethod(String.valueOf(System.currentTimeMillis()));
System.out.println(returnValue);
}
Особый случай при сравнение, сложный объект - создаем свой Matcher
Пример реализации собственного матчера, это позволяет написать матчер для особых случаев и особых объектов. @Test
public void customArgumentMatchersSample() throws Exception {
// create mock object
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// create custom matcher for method argument
Matcher matcher = new ArgumentMatcher() {
@Override
public boolean matches(Object argument) {
return argument.equals("expectedValue") || argument.equals("EXPECTED_VALUE") ;
}
};
// assign matcher to the method call
when(mockedObject.processMethod(argThat(matcher))).thenReturn("returnedValue");
// assert expected values
assertEquals("returnedValue", mockedObject.processMethod("expectedValue"));
assertEquals("returnedValue", mockedObject.processMethod("EXPECTED_VALUE"));
assertNull(mockedObject.processMethod("not mocked value"));
}
Стандартных матчеров недостаточно - используем Hamcrest
Пример использования Hamcreast matcher, больше информации об этом фреймворке можно посмотреть на странице: http://code.google.com/p/hamcrest/wiki/Tutorial @Test
public void hamrestMatcherUsageSample() throws Exception {
// create mock object
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// create stub for expected method calls
when(mockedObject.getStringValue()).thenReturn("_value1");
// using Hamcrest mathcers check expected method return values
assertThat(mockedObject.getStringValue(), org.hamcrest.Matchers.endsWith("1") );
assertThat(mockedObject.getStringValue(), org.hamcrest.Matchers.startsWith("_") );
/*
* Extract from Hamcrest JavaDoc:
Core
anything - always matches, useful if you don't care what the object under test is
describedAs - decorator to adding custom failure description
is - decorator to improve readability - see "Sugar", below
Logical
allOf - matches if all matchers match, short circuits (like Java &&)
anyOf - matches if any matchers match, short circuits (like Java ||)
not - matches if the wrapped matcher doesn't match and vice versa
Object
equalTo - test object equality using Object.equals
hasToString - test Object.toString
instanceOf, isCompatibleType - test type
notNullValue, nullValue - test for null
sameInstance - test object identity
Beans
hasProperty - test JavaBeans properties
Collections
array - test an array's elements against an array of matchers
hasEntry, hasKey, hasValue - test a map contains an entry, key or value
hasItem, hasItems - test a collection contains elements
hasItemInArray - test an array contains an element
Number
closeTo - test floating point values are close to a given value
greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo - test ordering
Text
equalToIgnoringCase - test string equality ignoring case
equalToIgnoringWhiteSpace - test string equality ignoring differences in runs of whitespace
containsString, endsWith, startsWith - test string matching
*/
}
Проверим сколько раз вызывался метод, а также, какой был порядок вызовов методов
Пример показывает как можно проверить количество вызовов методов а также порядок, в котором они вызываются. @Test
public void methodInvocationCountAndOrder() {
// create mock object
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
// call methods in mock
mockedObject.actionMethod();
mockedObject.actionMethod();
mockedObject.setStringValue("1");
mockedObject.setStringValue("2");
mockedObject.setStringValue("3");
mockedObject.setStringValue("3");
mockedObject.setStringValue("3");
mockedObject.setStringValue("4");
mockedObject.getStringValue();
mockedObject.getStringValue();
// verify method calls, also we check method invocation count
verify(mockedObject, times(2)).actionMethod();
verify(mockedObject, times(3)).setStringValue("3");
verify(mockedObject, atLeast(1)).getStringValue();
// create wrapper object, using this wrapper we can verify method's call order
InOrder inOrder = inOrder(mockedObject);
inOrder.verify(mockedObject).setStringValue("1");
inOrder.verify(mockedObject).setStringValue("2");
inOrder.verify(mockedObject, times(3)).setStringValue("3");
inOrder.verify(mockedObject).setStringValue("4");
}
Иногда правильный результат - ниодин метод не вызывался, проверим это
Проверка, что ни один метод не вызывался. @Test
public void verifyZeroInteractionsCheck(){
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
verifyZeroInteractions(mockedObject);
}
Проверка - вызываются только нужные методы
Пример показывает, как проверить, что вызываются только необходимые методы, другие не вызываются. @Test
public void verifyNoMoreInteractionsCheck() {
InterfaceForTest mockedObject = mock(InterfaceForTest.class);
mockedObject.actionMethod();
// verify, that method 'actionMethod' called
verify(mockedObject).actionMethod();
// verify, that method 'setStringValue()' never called
verify(mockedObject, never()).setStringValue("value");
// verify, that no more methods is called
verifyNoMoreInteractions(mockedObject);
}
Регестрируем spy() для класса, для некоторых методов определяем заглушку
Пример использования для тестов реального класса. При этом, мы можем проверить, вызывался ли метод, сколько раз и с какими параметрами. Также, есть возможность создавать заглушки только для некоторых методов, это очень удобно, когда мы хотим проверить поведение одного метода, используя заглушку для других. @Test
public void spyOnRealMethodAndPartialMocking() {
// create spy around real class, please note: we create real class instance
InterfaceForTest impl = spy(new InterfaceForTestImpl());
// set expected value only for one method
when(impl.getIntValue()).thenReturn(200);
// call method, method will be call on real class
impl.setStringValue("stringValue");
// we can verify, that method are called with expected input parameter
verify(impl).setStringValue("stringValue");
// in this case, we expect value set for mock, not real method call
assertEquals(200, impl.getIntValue() );
}
Комментариев нет:
Отправить комментарий