如何用mockito模拟一个构建器

And*_*rle 28 java unit-testing mockito

我有一个建设者:

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

在mockito中模拟构建器会使每个方法都为null.因此,有一种简单的方法可以让构建器在每次函数调用时返回自己,而不会使用模拟每个函数本身when().thenReturn.

Daw*_*ica 44

使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在创建模拟时,将其指定为默认答案.这将使你的模拟返回它自己的每个方法; 但是当你调用一个返回类型错误的方法时,它会像普通的模拟行为一样.

像这样创建你的模拟

Builder mockBuilder = mock( Builder.class, new SelfReturningAnswer());
Run Code Online (Sandbox Code Playgroud)

或者为这个类创建一个常量并写出类似的东西

@Mock( answer = SELF_RETURNING ) private Builder mockBuilder;
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.

  • "为这个类创建一个常量并写下"如何做到这一点??? (6认同)

Jef*_*ica 22

从Mockito 2.0(测试版)开始,有一个新的默认答案,RETURNS_SELFDavid Wallace的答案几乎相同.来自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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,它既出现在Mockito类上,也出现在Answers枚举上,因此它也与@Mock(answer = RETURNS_SELF)语法兼容.

  • 现在,这应该是公认的答案。 (3认同)

Mai*_*kov 11

您可以使用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
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不会给你一个模拟"所有各种构建器方法"的通用方法,以便它们总是返回这个,看到另一个答案就是你需要它.

  • 另外请注意,如果你得到深层存根顺序"错误"并投射结果,它会给你一些奇怪的消息,可能像`java.lang.ClassCastException:org.mockito.internal.creation.jmock.ClassImposterizer $ ClassWithSuperclassToWorkAroundCglibBug $ $ EnhancerByMockitoWithCGLIB $$ 851828bd无法转换为...` (2认同)
  • 我要补充的是,使用 RETURN_DEEP_STUBS 时“验证”不起作用 (2认同)