Mockito的argumentsCaptor示例


141

任何人都可以给我提供一个示例,说明如何使用org.mockito.ArgumentCaptor该类以及该类与Mockito附带的简单匹配器有何不同。

我阅读了提供的Mockito文档,但这些文档没有清楚说明,没有一个能够清晰地解释它。

Answers:


187

我同意@fge所说的内容,并且还要更多。让我们来看一个例子。考虑您有一个方法:

class A {
    public void foo(OtherClass other) {
        SomeData data = new SomeData("Some inner data");
        other.doSomething(data);
    }
}

现在,如果要检查内部数据,可以使用捕获器:

// Create a mock of the OtherClass
OtherClass other = mock(OtherClass.class);

// Run the foo method with the mock
new A().foo(other);

// Capture the argument of the doSomething function
ArgumentCaptor<SomeData> captor = ArgumentCaptor.forClass(SomeData.class);
verify(other, times(1)).doSomething(captor.capture());

// Assert the argument
SomeData actual = captor.getValue();
assertEquals("Some inner data", actual.innerData);

如果doSomething(data)mutate innerData,那么该更改会出现在中assertEquals("Some inner data", actual.innerData),还是会执行之前innerData按原样捕获? doSomething
科里·克莱恩

@CoryKlein OtherClass是一个模拟,按照现在的定义,它实际上doSomething()不会做任何事情,它只是记录传递的对象。这意味着它将在doSomething执行之前按原样捕获。
Slava Shpitalny

3
在中verifytimes(1)是默认值,可以省略。
Inego

ArgumentCaptor如何知道foo(other)发生了,因为只有在foo(other)调用之后才实例化它?
AvramPop

1
@AvramPop知道这是模拟对象的人。它内部包含有关模拟的许多信息。在所有这些信息中,它还包含每个方法及其参数的调用历史记录。调用该verify方法时,它将使用该信息来对您正在执行的验证进行匹配。对于每个参数,它询问它是否与它检查的特定调用匹配。选中ArgumentCaptor时,它仅存储使用其调用的值,因此当verify结束时,它将保存所有相关的调用。大致就是这样。希望对您有帮助
Slava Shpitalny

35

两个主要区别是:

  • 即使捕获单个参数,您也可以使用更明显的代码对此参数进行更详尽的测试;
  • 一个ArgumentCaptor可以捕捉比一次。

为了说明后者,请说您有:

final ArgumentCaptor<Foo> captor = ArgumentCaptor.forClass(Foo.class);

verify(x, times(4)).someMethod(captor.capture()); // for instance

然后,捕获程序将使您能够访问所有4个参数,然后可以分别对它们进行断言。

实际上,因为 VerificationMode不限于固定数量的调用;无论如何,如果您愿意,绑架者将使您能够访问所有这些对象。

这还有一个好处,即这种测试比必须实施自己的测试更容易编写 ArgumentMatcher的 -特别是如果您将Mockito与assertj结合使用。

哦,请考虑使用TestNG代替JUnit。


1
如果有多个参数传递到方法中-都是不同的类型怎么办?例如,如何实际验证布尔参数为true
IgorGanapolsky

21
您能否为您的评论提供一个解释:哦,请考虑使用TestNG代替JUnit。。为什么考虑呢?为什么要改变?
Navigatron

1
@IgorGanapolsky,您只需添加另一个ArgumentCaptor。ArgumentCaptor <BigDecimal> arg = ArgumentCaptor.forClass(BigDecimal.class); ArgumentCaptor <String> arg2 = ArgumentCaptor.forClass(String.class); 迈克尔·迈克尔=新迈克尔();michael.sayHi(j); verify(j).saySomething(arg.capture(),arg2.capture()); System.out.println(“ value是” + arg.getValue()); System.out.println(“ string是” + arg2.getValue());
johnwick0831

12

进行全面检查的步骤是:

准备捕获器:

ArgumentCaptor<SomeArgumentClass> someArgumentCaptor = ArgumentCaptor.forClass(SomeArgumentClass.class);

验证对依赖于组件(被测对象的合作者)times(1)的调用是默认值,因此需要添加它。

verify(dependentOnComponent, times(1)).send(someArgumentCaptor.capture());

将参数传递给协作者

SomeArgumentClass someArgument = messageCaptor.getValue();

someArgument可用于断言


-2

在这里,我给您一个回调方法的正确示例。因此,假设我们有一个类似方法login()的方法:

 public void login() {
    loginService = new LoginService();
    loginService.login(loginProvider, new LoginListener() {
        @Override
        public void onLoginSuccess() {
            loginService.getresult(true);
        }

        @Override
        public void onLoginFaliure() {
            loginService.getresult(false);

        }
    });
    System.out.print("@@##### get called");
}

我还将所有帮助程序类放在此处,以使示例更加清楚:loginService类

public class LoginService implements Login.getresult{
public void login(LoginProvider loginProvider,LoginListener callback){

    String username  = loginProvider.getUsername();
    String pwd  = loginProvider.getPassword();
    if(username != null && pwd != null){
        callback.onLoginSuccess();
    }else{
        callback.onLoginFaliure();
    }

}

@Override
public void getresult(boolean value) {
    System.out.print("login success"+value);
}}

而且我们的监听器LoginListener为:

interface LoginListener {
void onLoginSuccess();

void onLoginFaliure();

}

现在我只想测试类Login的方法login()

 @Test
public void loginTest() throws Exception {
    LoginService service = mock(LoginService.class);
    LoginProvider provider = mock(LoginProvider.class);
    whenNew(LoginProvider.class).withNoArguments().thenReturn(provider);
    whenNew(LoginService.class).withNoArguments().thenReturn(service);
    when(provider.getPassword()).thenReturn("pwd");
    when(provider.getUsername()).thenReturn("username");
    login.getLoginDetail("username","password");

    verify(provider).setPassword("password");
    verify(provider).setUsername("username");

    verify(service).login(eq(provider),captor.capture());

    LoginListener listener = captor.getValue();

    listener.onLoginSuccess();

    verify(service).getresult(true);

也不要忘记在测试类上方添加注释

@RunWith(PowerMockRunner.class)
@PrepareForTest(Login.class)

1
它不应该引用ArgumentCaptor吗?
Felipe Martins Melo

是的,我们正在捕获示例login(LoginProvider loginProvider,LoginListener回调)中传递给方法login()的侦听器
Vikram singh,

captor您的答案在哪里定义?
tom_mai78101

ArgumentCaptor <LoginListener> listenerCaptor = ArgumentCaptor.forClass(LoginListener.class);
维克拉姆·辛格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.