ChatGPT解决这个技术问题 Extra ChatGPT

Mockito 的 argumentCaptor 示例

谁能给我一个示例,展示如何使用 org.mockito.ArgumentCaptor 类以及它与 mockito 提供的 简单匹配器 有何不同。

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

也许您觉得这篇文章很有用:medium.com/javarevisited/… 它有一个简单的示例

S
Slava Shpitalny

我同意@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) 改变了 innerData,那么该更改会出现在 assertEquals("Some inner data", actual.innerData) 中,还是将 innerData 按原样 doSomething 执行之前捕获?
@CoryKlein OtherClass 是一个模拟,正如现在定义的那样, doSomething() 实际上不会做任何事情,它只是记录传递的对象。这意味着它将在执行 doSomething 之前按原样捕获。
verify 中,times(1) 是默认值,可以省略。
ArgumentCaptor 是如何知道 foo(other) 发生的,因为它仅在 foo(other) 调用之后才被实例化?
@AvramPop 知道这是模拟对象的人。它里面包含了很多关于mock的信息。在所有这些信息中,它还包含每个方法及其参数的调用历史记录。当您调用 verify 方法时,它会使用该信息针对您正在执行的验证运行匹配。对于每个参数,它都会询问它是否与它检查的特定调用匹配。检查 ArgumentCaptor 时,它只存储调用它的值,因此当 verify 结束时,它保存所有相关调用。它大致是如何工作的。希望能帮助到你
f
fge

两个主要区别是:

当你捕捉到一个参数时,你可以对这个参数进行更精细的测试,并使用更明显的代码;

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。


如果有多个参数传递到方法中——所有不同类型的参数怎么办?例如,您如何实际验证布尔参数是否为真。
您能否解释一下您的评论:哦,请考虑使用 TestNG 而不是 JUnit .. 为什么要考虑它?为什么要改变?
@IgorGanapolsky 您只需添加另一个 ArgumentCaptor。 ArgumentCaptor arg = ArgumentCaptor.forClass(BigDecimal.class); ArgumentCaptor arg2 = ArgumentCaptor.forClass(String.class);迈克尔迈克尔=新迈克尔();迈克尔.sayHi(j);验证(j).saySomething(arg.capture(),arg2.capture()); System.out.println("值为" + arg.getValue()); System.out.println("字符串为" + arg2.getValue());
L
Lho Ben

进行全面检查的步骤是:

首先,准备参数 captor :

ArgumentCaptor<ArgumentClass> argumentCaptor = ArgumentCaptor.forClass(ArgumentClass.class);

其次,验证对依赖组件(被测对象的协作者)的调用。

times(1) 是默认值,所以需要添加它。

verify(dependentOnComponent, times(1)).method(argumentCaptor.capture());

第三,使用captor的getValue()获取传递给collaborator的参数

ArgumentClass someArgument = messageCaptor.getValue();

四、使用 someArgument 进行断言


M
MauroB

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

该服务接收、转换为大写并修剪名称,然后调用存储库。

存储库“保存”字符串。

使用 ArgumentCaptor,我想知道哪个值被传递到存储库,然后检查它是否按预期被修剪和大写

个类: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);
    }
}

V
Vikram singh

这里我给你一个回调方法的恰当例子。所以假设我们有一个类似方法 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)

它不应该引用 ArgumentCaptor 吗?
是的,我们正在捕获在示例 login(LoginProvider loginProvider,LoginListener callback) 中传递给方法 login() 的侦听器
您的答案中定义的 captor 在哪里?
ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(LoginListener.class);