Как сделать методы mock to void с помощью mockito
Как издеваться над методами с типом возврата void?
я реализовал шаблон наблюдателя, но я не могу издеваться над ним с помощью Mockito, потому что я не знаю, как.
и я попытался найти пример в интернете, но не удалось.
мой класс выглядит так:
public class World {
List<Listener> listeners;
void addListener(Listener item) {
listeners.add(item);
}
void doAction(Action goal,Object obj) {
setState("i received");
goal.doAction(obj);
setState("i finished");
}
private string state;
//setter getter state
}
public class WorldTest implements Listener {
@Test public void word{
World w= mock(World.class);
w.addListener(this);
...
...
}
}
interface Listener {
void doAction();
}
система не запускается с помощью mock. =( Я хочу показать вышеупомянутое состояние системы. И утверждайте согласно им.
10 ответов
взгляните на Mockito API docs. Как упоминает связанный документ (пункт # 12), вы можете использовать любой из doThrow()
,doAnswer()
,doNothing()
,doReturn()
семейство методов от Mockito framework до методов mock void.
например,
Mockito.doThrow(new Exception()).when(instance).methodName();
или если вы хотите объединить его с последующими поведения,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
предполагая, что вы смотрите на издевательство над сеттером setState(String s)
в мире классов ниже код использует doAnswer
способ издеваться над setState
.
World mockWorld = mock(World.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(mockWorld).setState(anyString());
Я думаю, что нашел более простой ответ на этот вопрос, чтобы вызвать реальный метод только для одного метода (даже если он имеет void return), вы можете сделать это:
Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();
или вы можете вызвать реальный метод для всех методов этого класса, делая это:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
добавление к тому, что сказал @sateesh, когда вы просто хотите издеваться над методом void, чтобы предотвратить вызов теста, вы можете использовать Spy
таким образом:
World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();
когда вы хотите запустить тест, убедитесь, что вы вызываете метод в тесте на
решение так называемой проблемы заключается в использовании spy
Mockito.шпион.(..) вместо mock
Mockito.издеваться.(.).
шпион позволяет нам частично издеваться. Мокито хорош в этом деле. Поскольку у вас есть класс, который не является полным, таким образом Вы издеваетесь над некоторым требуемым местом в этом классе.
прежде всего: вы всегда должны импортировать Mockito static, таким образом, код будет гораздо более читаемым (и интуитивно понятным):
import static org.mockito.Mockito.*;
для частичного издевательства и сохранения оригинальной функциональности на остальных mockito предлагает "шпион".
вы можете использовать его следующим образом:
private World world = spy(World.class);
чтобы исключить метод из выполнения, вы можете использовать что-то вроде этого:
doNothing().when(someObject).someMethod(anyObject());
чтобы дать некоторое пользовательское поведение методу, используйте "когда" с "thenReturn":
doReturn("something").when(this.world).someMethod(anyObject());
для Больше примеров пожалуйста найдите образцы mockito в doc.
как издеваться над методами void с mockito - есть два варианта:
-
doAnswer
- Если мы хотим, чтобы наш издевательский метод void что-то сделал (издевайтесь над поведением, несмотря на пустоту). -
doThrow
- то естьMockito.doThrow()
Если вы хотите создать исключение из метода mocked void.
Ниже приведен пример того, как его использовать (не идеальный usecase, но просто хотел проиллюстрировать основные использование.)
@Test
public void testUpdate() {
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {
Customer customer = (Customer) arguments[0];
String email = (String) arguments[1];
customer.setEmail(email);
}
return null;
}
}).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old@test.com", "new@test.com");
//some asserts
assertThat(customer, is(notNullValue()));
assertThat(customer.getEmail(), is(equalTo("new@test.com")));
}
@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {
doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old@test.com", "new@test.com");
}
}
вы можете найти более подробную информацию о том, как mock и тест пустота методы с Mockito в моем посте как издеваться с Mockito (полное руководство с примерами)
добавление другого ответа в кучу (каламбур не предназначен)...
вам нужно вызвать метод doAnswer, если вы не можете\не хотите использовать spy's. Тем не менее, вам не обязательно катить свой собственный ответ. Существует несколько реализаций по умолчанию. В частности, CallsRealMethods.
на практике, это выглядит примерно так:
doAnswer(new CallsRealMethods()).when(mock)
.voidMethod(any(SomeParamClass.class));
или:
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
.voidMethod(any(SomeParamClass.class));
Я думаю, что ваши проблемы из-за структуры теста. Мне было трудно смешивать насмешку с традиционным методом реализации интерфейсов в тестовом классе (как вы это сделали здесь).
Если вы реализуете прослушиватель как макет, вы можете проверить взаимодействие.
Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();
в Java 8 это можно сделать немного чище, предполагая, что у вас есть статический импорт для org.mockito.Mockito.doAnswer
:
doAnswer(i -> {
// Do stuff with i.getArguments() here
return null;
}).when(*mock*).*method*(*methodArguments*);
на return null;
важно, и без него компиляция завершится с некоторыми довольно неясными ошибками, поскольку она не сможет найти подходящее переопределение для doAnswer
.
ExecutorService
это сразу же выполняет любой Runnable
перешло к execute()
может быть реализовано с помощью:
doAnswer(i -> {
((Runnable) i.getArguments()[0]).run();
return null;
}).when(executor).execute(any());
@ashley: работает на меня
public class AssetChangeListenerImpl extends AbstractAssetChangeListener implements AssetChangeListener { @Override public void onChangeEvent(final EventMessage message) throws EventHubClientException { execute(message); } } } public class AbstractAssetChangeListener { protected void execute( final EventMessage message ) throws EventHubClientException { executor.execute( new PublishTask(getClient(), message) ); } } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest { public void testExecute() throws EventHubClientException { EventMessage message = createEventMesage(EventType.CREATE); assetChangeListener.execute(message); verify(assetChangeListener, times(1)).execute(message); } }