Mockito is a Java-based framework for mocking objects in unit tests. The library allows complex verifications of method calls and input parameters. In this article, we are going to present the @Captor annotation used to capturing method argument values for future assertions.
2. Capturing the arguments
@Captor annotation, which always occurs in conjunction with ArgumentCaptor, allows defining special objects used to capturing the arguments passed to a method that we want to inspect. Capturing input parameters is extremely useful for testing methods called in other methods. Sometimes this is the only way to test logic that stands behind some huge implementation that doesn't return any "on the way".
Let's start with a simple example:
In this sample JUnit test, we are using @Mock annotation to create a mock object of the List type. Then we used @Captor annotation to define the new ArgumentCaptor field of type String to store our captured arguments.
First, we add two String values to our list: "one", "two". Secondly, we are using the verify(...) method with the ArgumentCaptor to capture that strings.
Every ArgumentCaptor has two methods getValue() and getAllValues().
The getValue() can be used when we have captured an argument from a single method call. If the method was called multiple times getValue() will return the latest captured value.
The getAllValues returns the list of arguments if the method was called more than once.
3. Using @Captor in test
Previously we presented a simple JUnit test, now let's check an example from a more complex application:
Let's consider we have three services:
for sending emails:
We have also a complex service that uses these three services. It has a method businessLogic which is processing some data and calling other services. Note that this method doesn't return any value:
We want to write a test that will verify if calculations after calling each service are correct:
SimpleMailService, SimpleMultiplicationService and SimpleSummingService services are annotated with @Mock annotation but in test we want to call the actual implementation that why we used: .thenCallRealMethod() method. Mocked objects are injected into the class that we want to test - ComplexBusinessLogicService.
To test what happens inside a complex method we used several ArgumentCaptor objects for Double and String types. The rest of the tests are verifications if calculated parameters are equal to expected values.
In this article, we looked at how to use @Captor with an ArgumentCaptor object. We presented simple examples, and more complex than could be found in real-life applications with complicated business logic.
As usual, code snippets used in this tutorial are available over on GitHub.