Методы обрушения, которые манипулируют параметрами с помощью mockito
У меня следующая ситуация:
class Worker {
public Integer somework() {
Integer k=0;
Helper h= new Helper();
h.change(k);
return k;
}
}
class Helper {
public void change(Integer k) {
//k = Some calcs
}
}
Я делаю unitests для Worker
и, очевидно, хочу издеваться над классом Helper
, чтобы его метод change
всегда помещал 1 в k
.
Моя реальная ситуация сложнее, но этот код представляет проблему. Спасибо за помощь.
Ответы
Ответ 1
Я бы изменил сигнатуру метода и заставил использовать экземпляр Helper
в качестве аргумента. Вызывающий вызывал бы помощника и передавал его методу somework
. Тест прошел бы мимоходом.
Если это невозможно, по крайней мере вызовите защищенный метод factory для создания помощника и издевайтесь над этим методом factory при тестировании метода somework
, чтобы он возвращал вспомогательный помощник:
class Worker {
public Integer somework(){
Integer k=0;
Helper h= createHelper();
h.change(k);
return k;
}
// this method may be mocked when testing somework, to return a mock helper.
protected Helper createHelper() {
return new Helper();
}
}
Ответ 2
У меня есть метод с определением вроде этого:
class Template{
public void process(Object rootMap, StringWriter out){
.......
}
}
Я покажу вам, как вы можете изменить/изменить ссылку "out" (StringWriter).
private final Template mocktTemplate = mock(Template.class);
doAnswer(new Answer<StringWriter>() {
public StringWriter answer(InvocationOnMock invocation)
throws Throwable {
Object[] args = invocation.getArguments();
if (args[1] instanceof StringWriter) {
StringWriter stringWriter = (StringWriter) args[1];
stringWriter.write("Email message");
}
return null;
}
}).when(this.mocktTemplate).process(anyObject(),any(StringWriter.class));
Теперь, когда вы делаете фактический вызов, например:
msgBodyTemplate.process(model, msgBodyWriter);
значение Stringbuffer ref в msgBodyWriter будет "Сообщение электронной почты"; независимо от его более раннего значения.
Ответ 3
To @JB Нижне точка, да, это хорошо для рефакторинга для проверки. Часто рефакторинг, чтобы сделать код более надежным, приводит к коду, который лучше по другим причинам - разделение проблем и тому подобное. Это не всегда можно сделать. Скажите, что это не ваш код, или у вас есть другое требование оставить его в покое (потому что многие другие классы полагаются на то, что это так) или что-то еще.
Если я понимаю, что вам нужно сделать, я думаю, вы можете сделать это со шпионом:
Worker workerUnderTest = new Worker();
Worker spiedWorkerUT = spy(workerUnderTest);
Helper mockHelper = mock(Helper.class);
when(spiedWorkerUT.createHelper()).thenReturn(mockHelper);
Integer actual = spiedWorkerUT.someWork();
verify(mockHelper).change(0);
Затем используйте spiedWorkerUT вместо workUnderTest для запуска ваших тестов.
Не всегда можно избежать создания экземпляра того, что вы хотите высмеять. Для этого существует PowerMock.
Helper mockHelper = mock(Helper.class);
whenNew(Helper.class).withNoArguments().thenReturn(mockHelper);
Ответ 4
Я думаю, что doAnswer - лучший метод работы с методом void, когда метод обрабатывает заданные параметры.
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Mock mock = invocation.getMock();
return null;
}})
.when(mock).someMethod();
В принципе, после получения аргументов вы можете сделать любую модификацию, которую хотите. Там сообщение в блоге, объясняющее это немного.