Mockito의 argumentCaptor의 예


141

누구든지 org.mockito.ArgumentCaptor수업 사용 방법 과 mockito와 함께 제공되는 간단한 매처 와 다른 점 을 보여주는 예를 제공해 주 시겠습니까?

제공된 mockito 문서를 읽었지만 그 내용을 명확하게 설명하지는 못하며 명확하게 설명 할 수는 없습니다.

답변:


187

@fge가 말한 것에 더 동의합니다. 예를 보자. 방법이 있다고 생각하십시오.

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

내부 데이터를 확인하려면 captor를 사용할 수 있습니다.

// 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 The OtherClassmock은 모의이며, 현재 정의 된대로 doSomething()실제로 아무 것도하지 않고 전달 된 객체를 단순히 기록합니다. 즉, doSomething실행 되기 전에 그대로 캡처됩니다 .
Slava Shpitalny

3
이어 verify, times(1)기본값이며 생략 할 수 있습니다.
Inego

ArgumentCaptor는 foo (other)가 foo (other) 호출 후에 만 ​​인스턴스화되었으므로 foo (other)가 발생했음을 어떻게 알 수 있습니까?
AvramPop

1
@AvramPop 이것이 모의 객체라는 것을 아는 사람. 모의에 대한 많은 정보가 들어 있습니다. 이 모든 정보에는 매개 변수가있는 각 메서드의 통화 기록도 포함되어 있습니다. verify메소드 를 호출하면 해당 정보를 사용하여 수행중인 확인과 일치하는 항목을 실행합니다. 모든 매개 변수에 대해 검사하는 특정 호출과 일치하는지 묻습니다. ArgumentCaptor를 검사하면 호출 된 값을 저장하기 만하면 verify끝날 때 모든 관련 호출을 보유합니다. 그것은 대략 어떻게 작동합니다. 도움이
되길 바랍니다

35

두 가지 주요 차이점은 다음과 같습니다.

  • 단일 인수조차도 포착하면이 인수에 대해보다 명확한 테스트를 통해보다 명확한 코드를 작성할 수 있습니다.
  • ArgumentCaptor캡처 할 수 있습니다 번 이상.

후자를 설명하기 위해 다음과 같이 말합니다.

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

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

그러면 캡터는 4 개의 모든 인수에 대한 액세스 권한을 부여 할 수 있으며이를 통해 개별적으로 어설 션을 수행 할 수 있습니다.

a 또는 VerificationMode고정 된 수의 호출에 국한되지 않기 때문에,이 또는 임의의 수의 인수 ; 어쨌든, 캡터는 원한다면 그들 모두에게 접근 권한을 부여 할 것입니다.

이것은 또한 자신 ArgumentMatcher의 구현을 수행하는 것보다, 특히 mockito와 assertj를 결합하는 경우 보다 그러한 테스트를 작성하는 것이 훨씬 쉽다는 이점이 있습니다 .

아, JUnit 대신 TestNG 사용을 고려하십시오.


1
메소드에 여러 개의 매개 변수가 전달되면 모든 다른 유형은 어떻게됩니까? 예를 들어 부울 매개 변수가 true 인지 실제로 어떻게 확인합니까?
IgorGanapolsky

21
귀하의 의견에 대한 설명을 제공해 줄 수 있습니까? 아, JUnit 대신 TestNG를 사용해보십시오. . 왜 생각해? 왜 변화 하는가?
Navigatron 2016 년

1
@ IgorGanapolsky 당신은 단지 다른 ArgumentCaptor를 추가합니다. ArgumentCaptor <BigDecimal> arg = ArgumentCaptor.forClass (BigDecimal.class); ArgumentCaptor <문자열> arg2 = ArgumentCaptor.forClass (String.class); 마이클 마이클 = 새로운 마이클 (); michael.sayHi (j); verify (j) .saySomething (arg.capture (), arg2.capture ()); System.out.println ( "값은"+ arg.getValue ()); System.out.println ( "문자열은"+ 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);
Vikram 싱
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.