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実行されますか?
Cory Klein

@CoryKleinこれOtherClassはモックであり、現在定義されているため、doSomething()実際には何も実行せず、渡されたオブジェクトを記録するだけです。つまり、doSomething実行される前にそのままキャプチャされます。
Slava Shpitalny

3
ではverifytimes(1)がデフォルトであり、省略できます。
Inego

ArgumentCaptorは、foo(other)が呼び出された後にのみインスタンス化されるため、foo(other)が発生したことをどのようにして知るのですか?
AvramPop

1
@AvramPopこれを知っているのはモックオブジェクトです。モックに関する多くの情報が含まれています。そのすべての情報の内部には、各メソッドのパラメーターを含む呼び出し履歴も含まれています。verifyメソッドを呼び出すと、その情報を使用して、実行している検証に対して照合が実行されます。すべてのパラメータについて、チェックする特定の呼び出しと一致するかどうかを尋ねます。ArgumentCaptorがチェックされると、それは呼び出された値を格納するだけなので、verify終了すると、関連するすべての呼び出しを保持します。おおよその動作です。それがお役に立てば
幸い

35

主な2つの違いは次のとおりです。

  • 単一の引数をキャプチャする場合でも、この引数に対して、より明確なコードを使用して、はるかに複雑なテストを実行できます。
  • an ArgumentCaptor複数回キャプチャできます。

後者を説明するために、あなたが持っているとしましょう:

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

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

その後、キャプターは4つの引数すべてにアクセスできるようになり、その後、個別にアサーションを実行できます。

実際には、これは任意の数の引数VerificationModeです。いずれにせよ、キャプターは必要に応じてそれらすべてにアクセスできます。

これには、ArgumentMatcher特にmockitoとassertjを組み合わせた場合に、独自のs を実装する必要があるよりも、そのようなテストを(imho)作成する方がはるかに簡単であるという利点もあります。

JUnitの代わりにTestNGを使用することを検討してください。


1
メソッドに複数のパラメーターが渡された場合はどうなりますか?すべての異なるタイプですか?たとえば、ブール値パラメーターがtrueであることを実際にどのように確認しますか?
IgorGanapolsky 2017

21
コメントについて説明してください。ああ、JUnitの代わりにTestNGの使用を検討してください。。なぜそれを考慮するのですか?なぜ変わるのですか?
Navigatron 2017年

1
@IgorGanapolskyあなたは別のArgumentCaptorを追加するだけです。ArgumentCaptor <BigDecimal> arg = ArgumentCaptor.forClass(BigDecimal.class); ArgumentCaptor <String> arg2 = ArgumentCaptor.forClass(String.class); マイケルマイケル=新しいマイケル(); michael.sayHi(j); verify(j).saySomething(arg.capture()、arg2.capture()); System.out.println( "value is" + arg.getValue()); System.out.println( "string is" + 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

ここでは、1つのコールバックメソッドの適切な例を示します。メソッド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 callback)のメソッドlogin()に渡されたリスナーをキャプチャしています
Vikram

captorあなたの答えのどこに定義されていますか?
tom_mai78101

ArgumentCaptor <LoginListener> listenerCaptor = ArgumentCaptor.forClass(LoginListener.class);
Vikram sing
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.