关于Mockito的argumentCaptor的例子

Ujj*_*wal 111 java junit unit-testing mockito

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

我阅读了所提供的mockito文档,但这些文档没有清楚地说明,也没有能够清楚地解释它.

Sla*_*lny 148

我同意@fge所说的更多内容.让我们看一下例子.考虑一下你有一个方法:

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

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

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

  • 在“verify”中,“times(1)”是默认值,可以省略。 (4认同)
  • @AvramPop 知道这是模拟对象的人。它里面包含了很多关于模拟的信息。在所有这些信息中,它还包含每个方法及其参数的调用历史记录。当您调用“verify”方法时,它会使用该信息来针对您正在执行的验证运行匹配。对于每个参数,它都会询问它是否与它检查的特定调用相匹配。当 ArgumentCaptor 被检查时,它只是存储调用它的值,因此当“verify”结束时,它保存所有相关的调用。大致是这样的。希望能帮助到你 (4认同)

fge*_*fge 29

两个主要区别是:

  • 当你捕获一个单独的参数时,你可以对这个参数进行更详细的测试,并且使用更明显的代码;
  • 一个ArgumentCaptor可以捕捉更比一次.

为了说明后者,请说:

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

verify(x, times(4)).someMethod(captor.capture()); // for instance
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 您能否为您的评论提供解释:_Oh,请考虑使用TestNG而不是JUnit._.为什么要考虑它?为何改变? (15认同)
  • @IgorGanapolsky,您只需添加另一个 ArgumentCaptor 即可。ArgumentCaptor&lt;BigDecimal&gt; arg = ArgumentCaptor.forClass(BigDecimal.class); ArgumentCaptor&lt;String&gt; arg2 = ArgumentCaptor.forClass(String.class); 迈克尔·迈克尔 = new 迈克尔(); 迈克尔.sayHi(j); 验证(j).saySomething(arg.capture(), arg2.capture()); System.out.println("值为" + arg.getValue()); System.out.println("字符串是 " + arg2.getValue()); (2认同)

小智 11

我创建了这个示例,它模拟一个非常简单的服务,该服务使用存储库来保存字符串(无依赖项注入,无实体),只是为了快速教授 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Lho*_*Ben 8

进行全面检查的步骤是:

准备捕获器:

ArgumentCaptor<SomeArgumentClass> someArgumentCaptor = ArgumentCaptor.forClass(SomeArgumentClass.class);
Run Code Online (Sandbox Code Playgroud)

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

verify(dependentOnComponent, times(1)).send(someArgumentCaptor.capture());
Run Code Online (Sandbox Code Playgroud)

将参数传递给协作者

SomeArgumentClass someArgument = messageCaptor.getValue();
Run Code Online (Sandbox Code Playgroud)

someArgument可用于断言