关于Mockito的argumentCaptor的例子

时间:2016-03-27 21:44:24

标签: java unit-testing junit mockito

任何人都可以请我提供一个示例,说明org.mockito.ArgumentCaptor类的用法是什么,以及它与mockito提供的简单匹配器有何不同。

我阅读了所提供的mockito文档,但这些文档没有清楚地说明, 他们都无法清楚地解释它。

5 个答案:

答案 0 :(得分:119)

我同意@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);

答案 1 :(得分:27)

两个主要区别是:

  • 当你捕获一个参数时,你可以对这个参数进行更详细的测试,并且代码更明显;
  • ArgumentCaptor可以捕获更多而不是一次。

为了说明后者,请说:

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

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

然后,捕获者将能够访问所有4个参数,然后您可以单独执行断言。

事实上这个或任意数量的参数,因为VerificationMode不限于固定数量的调用;无论如何,如果您愿意,捕获者将允许您访问所有这些。

这样做的好处是,这些测试(imho)比实现自己的ArgumentMatcher更容易编写 - 特别是如果你将mockito与assertj结合起来。

哦,请考虑使用TestNG而不是JUnit。

答案 2 :(得分:3)

进行全面检查的步骤是:

准备捕获者:

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

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

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

将参数传递给协作者

SomeArgumentClass someArgument = messageCaptor.getValue();

someArgument可用于断言

答案 3 :(得分:1)

我创建了这个示例来模拟一个非常简单的服务,该服务使用存储库保存字符串(无依赖注入,无实体),只是为了快速教授 ArgumentCaptor。

  • 服务接收、转换为大写并修剪名称,然后调用存储库。
  • 存储库“保存”了字符串。
  • 使用 ArgumentCaptor,我想知道将哪个值传递给存储库,然后检查它是否按预期进行了修剪和大写

3 个类:PersonService、PersonRepository 和 PersonServiceTest(省略包)

public class PersonService {

    private PersonRepository personRepository;

    public void setPersonRepository(final PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    public void savePerson(final String name) {
        this.personRepository.save(name.toUpperCase().trim());
    }

}

public class PersonRepository {

    public void save(final String person) {
        System.out.println(".. saving person ..");
    }
}


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

class PersonServiceTest {

    @Test
    void testPersonService() {

        // Create the repository mock
        final PersonRepository personRepositoryMock = mock(PersonRepository.class);

        // Create the service and set the repository mock
        final PersonService personService = new PersonService();
        personService.setPersonRepository(personRepositoryMock);

        // Save a person
        personService.savePerson("Mario ");

        // Prepare an ArgumentCaptor to capture the value passed to repo.saveMethod
        final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);

        // Capture the argument passed in the unique method invocation
        verify(personRepositoryMock, times(1)).save(captor.capture());

        // Check if the captured value is the expected one
        final String capturedParameter = captor.getValue();
        assertEquals("MARIO", capturedParameter);
    }
}

答案 4 :(得分:0)

在这里,我给您提供一个回调方法的正确示例。 因此,假设我们有一个类似方法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)