我有一个建设者:
class Builder{
private String name;
private String address;
public Builder setName(String name){
this.name = name;
return this;
}
public Builder setAddress(String address){
this.address = address;
return this;
}
}
在mockito中模拟构建器会使每个方法都为null。因此,有一种简单的方法可以让构建器在每次函数调用时返回自己,而不使用when().thenReturn
来模拟每个函数本身。
答案 0 :(得分:40)
使用RETURN_DEEP_STUBS的问题在于,每次调用方法时都会获得不同的模拟。我想从你的问题中你想要使用一个默认的Answer,它实际上返回了调用它的mock,对于每个具有正确返回类型的方法。这可能类似于以下内容。请注意,我没有对此进行测试,因此它可能包含拼写错误,但我希望无论如何都有明确的意图。
import static org.mockito.Mockito.RETURNS_DEFAULTS;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class SelfReturningAnswer implements Answer<Object>{
public Object answer(InvocationOnMock invocation) throws Throwable {
Object mock = invocation.getMock();
if( invocation.getMethod().getReturnType().isInstance( mock )){
return mock;
}
else{
return RETURNS_DEFAULTS.answer(invocation);
}
}
}
然后,在创建模拟时,将其指定为默认答案。这将使你的模拟返回它自己的每个方法;但是当你调用一个返回类型错误的方法时,它会像普通的模拟行为一样。
像这样创建你的模拟
Builder mockBuilder = mock( Builder.class, new SelfReturningAnswer());
或为此类创建一个常量并编写类似
的内容@Mock( answer = SELF_RETURNING ) private Builder mockBuilder;
希望有所帮助。
答案 1 :(得分:17)
从Mockito 2.0(测试版)开始,RETURNS_SELF
有一个新的默认答案,其行为几乎与David Wallace's answer完全相同。来自Mockito文档的示例:
@Test
public void use_full_builder_with_terminating_method() {
HttpBuilder builder = mock(HttpBuilder.class, RETURNS_SELF);
HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder);
String response = "StatusCode: 200";
when(builder.request()).thenReturn(response);
assertThat(requester.request("URI")).isEqualTo(response);
}
请注意,它同时显示在Mockito
类和Answers
枚举上,因此它也与@Mock(answer = RETURNS_SELF)
语法兼容。
答案 2 :(得分:10)
您可以使用RETURN_DEEP_STUBS来模拟链式API。
如果你知道你的建造者的确切顺序,这里有一个如何使用它的例子:
Builder b = Mockito.mock(Builder.class, RETURNS_DEEP_STUBS);
when(b.setName("a name").setAddress("an address")).thenReturn(b);
assert b.setName("a name").setAddress("an address") == b; // this passes
不幸的是,这不会给你一种模仿“所有各种构建器方法”的通用方法,以便它们总是返回这个,看到另一个答案就是你需要它。