com.fitbur.mockito.ArgumentCaptor Maven / Gradle / Ivy
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package com.fitbur.mockito;
import static com.fitbur.mockito.internal.util.Primitives.defaultValue;
import java.util.List;
import com.fitbur.mockito.internal.matchers.CapturingMatcher;
/**
* Use it to capture argument values for further assertions.
*
*
* Mockito verifies argument values in natural java style: by using an equals() method.
* This is also the recommended way of matching arguments because it makes tests clean & simple.
* In some situations though, it is helpful to assert on certain arguments after the actual verification.
* For example:
*
* ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
* verify(mock).doSomething(argument.capture());
* assertEquals("John", argument.getValue().getName());
*
*
* Example of capturing varargs:
*
* //capturing varargs:
* ArgumentCaptor<Person> varArgs = ArgumentCaptor.forClass(Person.class);
* verify(mock).varArgMethod(varArgs.capture());
* List expected = asList(new Person("John"), new Person("Jane"));
* assertEquals(expected, varArgs.getAllValues());
*
*
*
* Warning: it is recommended to use ArgumentCaptor with verification but not with stubbing.
* Using ArgumentCaptor with stubbing may decrease test readability because captor is created outside of assert (aka verify or 'then') block.
* Also it may reduce defect localization because if stubbed method was not called then no argument is captured.
*
*
* In a way ArgumentCaptor is related to custom argument matchers (see javadoc for {@link ArgumentMatcher} class).
* Both techniques can be used for making sure certain arguments where passed to mocks.
* However, ArgumentCaptor may be a better fit if:
*
* - custom argument matcher is not likely to be reused
* - you just need it to assert on argument values to complete verification
*
* Custom argument matchers via {@link ArgumentMatcher} are usually better for stubbing.
*
*
* This utility class *don't do any type checks*, the generic signatures are only there to avoid casting
* in your code.
*
* There is an annotation that you might find useful: @{@link Captor}
*
* See the full documentation on Mockito in javadoc for {@link Mockito} class.
*
* @see Captor
* @since 1.8.0
*/
public class ArgumentCaptor {
private final CapturingMatcher capturingMatcher = new CapturingMatcher();
private final Class extends T> clazz;
private ArgumentCaptor(Class extends T> clazz) {
this.clazz = clazz;
}
/**
* Use it to capture the argument. This method must be used inside of verification.
*
* Internally, this method registers a special implementation of an {@link ArgumentMatcher}.
* This argument matcher stores the argument value so that you can use it later to perform assertions.
*
* See examples in javadoc for {@link ArgumentCaptor} class.
*
* @return null or default values
*/
public T capture() {
Mockito.argThat(capturingMatcher);
return defaultValue(clazz);
}
/**
* Returns the captured value of the argument. When capturing varargs use {@link #getAllValues()}.
*
* If verified method was called multiple times then this method it returns the latest captured value.
*
* See examples in javadoc for {@link ArgumentCaptor} class.
*
* @return captured argument value
*/
public T getValue() {
return this.capturingMatcher.getLastValue();
}
/**
* Returns all captured values. Use it when capturing varargs or when the verified method was called multiple times.
* When varargs method was called multiple times, this method returns merged list of all values from all invocations.
*
* Example:
*
* mock.doSomething(new Person("John");
* mock.doSomething(new Person("Jane");
*
* ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
* verify(mock, times(2)).doSomething(peopleCaptor.capture());
*
* List<Person> capturedPeople = peopleCaptor.getAllValues();
* assertEquals("John", capturedPeople.get(0).getName());
* assertEquals("Jane", capturedPeople.get(1).getName());
*
*
* Example of capturing varargs:
*
* mock.countPeople(new Person("John"), new Person("Jane"); //vararg method
*
* ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
*
* verify(mock).countPeople(peopleCaptor.capture());
*
* List expected = asList(new Person("John"), new Person("Jane"));
* assertEquals(expected, peopleCaptor.getAllValues());
*
* See more examples in javadoc for {@link ArgumentCaptor} class.
*
* @return captured argument value
*/
public List getAllValues() {
return this.capturingMatcher.getAllValues();
}
/**
* Build a new ArgumentCaptor
.
*
* Note that an ArgumentCaptor
*don't do any type checks*, it is only there to avoid casting
* in your code. This might however change (type checks could be added) in a
* future major release.
*
* @param clazz Type matching the parameter to be captured.
* @param Type of clazz
* @param Type of object captured by the newly built ArgumentCaptor
* @return A new ArgumentCaptor
*/
public static ArgumentCaptor forClass(Class clazz) {
return new ArgumentCaptor(clazz);
}
}