我有以下情况:
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
}
}
我正在为Worker
制作unitests,显然我想模仿Helper
课程,以便他的change
方法始终将1放入k
。
我的实际情况更复杂,但此代码代表了问题。谢谢你的帮助。
答案 0 :(得分:18)
我有一个定义如下的方法:
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);
msgBodyWriter中Stringbuffer ref的值为“Email message”;不论它早期的价值。
答案 1 :(得分:4)
至于@JB Nizet的观点,是的,重构可测试性是件好事。通常,重构以使代码更易于测试会导致代码更好地用于其他原因 - 分离关注点等等。这并不总是可行的。说这不是你的代码,或者你有其他要求不管它(因为许多其他类依赖于它的方式)或其他什么。
如果我理解你需要做什么,我认为你可以用间谍来做:
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而不是workerUnderTest来运行测试。
并不总是可以避免实例化你想要模拟的东西。为此,有PowerMock。
Helper mockHelper = mock(Helper.class);
whenNew(Helper.class).withNoArguments().thenReturn(mockHelper);
答案 2 :(得分:4)
我认为doAnswer是处理void方法的最佳方法,其中方法操纵给定的参数。
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Mock mock = invocation.getMock();
return null;
}})
.when(mock).someMethod();
基本上,在获得参数后,您可以进行任何您想要的修改。有blog post解释了一下。
答案 3 :(得分:2)
我会更改方法签名并使其以Helper
实例作为参数。调用者将创建帮助程序并将其传递给somework
方法。测试将通过模拟助手。
如果无法做到这一点,至少调用受保护的工厂方法来创建帮助程序,并在测试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();
}
}