Contents

Using Mockito ArgumentCaptor

Introduction

This post will look at the ArgumentCaptor of Mockito and how to use it in our unit tests.

We will use the following two classes for the examples in this post. We have a Dog class with a method to name the dog and an Owner class with a method to adopt a dog and name it. We will use ArgumentCaptor to capture the name the owner will give to the dog.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Owner{
    public void adoptDog(Dog dog){
        dog.giveName("Max");
    }
}

class Dog {
    public void giveName(String name) {
        System.out.println("name = " + name);
    }
}

Using ArgumentCaptor

An ArgumentCaptor captures the argument passed to a method. For our example, we will use it to capture a string argument. This way, we can verify if the argument passed to the method is what we expected it to be.

To create an ArgumentCaptor, we can use this:

1
ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);

This code will create an ArgumentCaptor to capture strings. Next, we need to capture the arguments, which can be done within a Mockito.verify.

1
Mockito.verify(dog).giveName(stringArgumentCaptor.capture());

The entire unit test to verify the name of the dog looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ArgumentCaptors {

    @Test
    void testName() {
        // create a mock
        Dog dog = mock(Dog.class);

        Owner owner = new Owner();
        // Use the owner to name the dog
        owner.adoptDog(dog);

        // create an ArgumentCaptor for String
        ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);

        // capture the name of the dog
        Mockito.verify(dog).giveName(stringArgumentCaptor.capture());
        // get the value out of the ArgumentCaptor 
        String captorValue = stringArgumentCaptor.getValue();

        Assertions.assertEquals("Max", captorValue);
    }

}

ArgumentCaptor annotation

We can also use annotations to create an ArgumentCaptor for us. We need to add an annotation above our test class to do that.

  • For Junit5, you need to add @ExtendWith(MockitoExtension.class).
  • For Junit4, you need to add @RunWith(MockitoJUnitRunner.class).

I will be using Junit5 for the example. To create an ArgumentCaptor with an annotation, we only need to add this annotated field to the class:

1
2
@Captor
ArgumentCaptor<String> stringArgumentCaptor;

Mockito will initialize this with an ArgumentCaptor that captures String.

With annotations, our unit test class will look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@ExtendWith(MockitoExtension.class)
public class ArgumentCaptors {

    @Captor
    ArgumentCaptor<String> stringArgumentCaptor;

    @Test
    void testName(){
        Dog dog = mock(Dog.class);

        Owner owner = new Owner();
        owner.adoptDog(dog);

        Mockito.verify(dog).giveName(stringArgumentCaptor.capture());
        String captorValue = stringArgumentCaptor.getValue();

        Assertions.assertEquals("Max", captorValue);
    }

}

Java 8 alternative for ArgumentMatcher

For less complex use cases, we can also use Lambda matcher to verify the input of a method. With argThat, we create a matcher that validates the input of a method. In the example below, we create this matcher argThat(name -> "Max".equals(name)) that verifies that the name of the dog is Max.

1
2
3
4
5
6
7
8
9
@Test
void testNameLambdaMatcher() {
    Dog dog = mock(Dog.class);

    Owner owner = new Owner();
    owner.adoptDog(dog);

    Mockito.verify(dog).giveName(argThat(name -> "Max".equals(name)));
}

This is better for less complex use cases because it makes your unit tests easier to read and write. See this post if you want to know more about mockito lambda matchers

Conclusion

In this post, we looked at how to use the argumentCaptor in a Unit test. We also looked at the argumentMatcher as an alternative to verify the input to our unit tests.

Further reading

More about testing in Java:

Have a question or idea?

Thank you for reading my post. Have any questions about this topic or an idea for a new topic? Please reach out to me on Twitter or send me an email.

If you want to read more about Java when I write about it – you can follow me on Twitter.