Mockito's argumentCaptor的例子

谁能给我一个例子,说明如何使用org.mockito.ArgumentCaptor类,以及它是如何不同于简单的匹配器提供的mockito。

我阅读了提供的模拟文档,但那些并没有说明清楚,他们都不能解释清楚。

216981 次浏览

两个主要的区别是:

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

为了说明后者,假设你有:

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


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

然后捕获器将允许您访问所有4个参数,然后您可以分别对它们执行断言。

这个或任何数量的实参,因为VerificationMode不局限于固定数量的调用;无论如何,如果你愿意,抓捕者会给你所有的权限。

这样做的另一个好处是,这样的测试更容易编写,而不是必须实现自己的__abc0——特别是如果你将mockito和assertj结合在一起。

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

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

进行全面检查的步骤如下:

第一个,准备参数捕获器:

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

第二个,验证对依赖组件(被测对象的合作者)的调用。

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

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

第三,使用捕获器的getValue()获取传递给协作器的参数

ArgumentClass someArgument = messageCaptor.getValue();

第四,使用someArgument进行断言

这里我给你一个适当的回调方法的例子。 假设我们有一个方法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");
}
我还把所有的helper类放在这里,使示例更清楚: loginService类< / p >
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 as:

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

不要忘记在测试类上面添加注释as

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

我创建了这个例子来模拟一个非常简单的服务,它使用一个存储库来保存一个String(没有依赖注入,没有实体),只是为了快速地教授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);
}
}

你可能想要结合使用verify()和ArgumentCaptor来确保在测试中执行,并使用ArgumentCaptor来计算参数:

ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());
    

参数的值显然可以通过argument. getvalue()进行进一步的操作/检查或任何你想做的事情。

使用注释这个和大多数事情@间谍,@Mock, @Captor等。

下面是一个示例(使用JUnit 5):

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


@ExtendWith(MockitoExtension.class)
public class TestBlam
{
@Captor
private ArgumentCaptor<SomeData> captorSomeData;


private Blam classToTest;


@Mock
private OtherClass mockOtherClass;


@BeforeEach
void beforeEach()
{
classToTest = new Blam();
}


@Test
void foo_allGood_success()
{
SomeData actualSomeData;


classToTest.foo(mockOtherClass);
    

verify(mockOtherClass).doSomething(captorSomeData.capture());
    

actualSomeData = captorSomeData.getValue();
    

assert(stuff about actualSomeData);
}
}