Skip to content

jameskennard/mockito-collections

Repository files navigation

Mockito-Collections

This project aims to compliment the Java Mockito library by adding the ability to inject Collections of Mocks into objects under test; Thereby eradicating the need to manually set Collections of Mocks. See https://groups.google.com/forum/#!topic/mockito/CfxbGNOewuI for initial ideas.

Build Status

The Problem

When you use Mockito's @InjectMocks annotation or MockitoAnnotations.initMocks(Object) mocks will not be injected into Collections. This results in the need to do so manually for example:

@InjectMocks
private MyDelegate delegate;

@Mock
private MyListener listener1;

@Mock
private MyListener listener2;

@Before
public void setup() {
    Set<MyListener> listeners = new LinkedHashSet<MyListener>();
    listeners.add(listener1);
    listeners.add(listener2);
    delegate.setListeners(listeners);
}

We end up writing boilerplate code again and again specifically to deal with this scenario. This is laborious and a pain to maintain, especially when injecting many Collections.

The Solution

The solution proposed by this project is to inspect the generics of the Collection fields in the class under test, denoted by the @InjectMocks annotation. Once the type of the elements of the Collection have been established, create a new Collection and add all of the mocks of the correct type to the Collection. And finally, inject the new Collection into the relevant field.

In an ideal scenario, we would be able to rely on the MockitoJUnitRunner to deal with this for us by specifying some sort of injection strategy. This is something Mockito does not yet provide. For now, the workaround is to provide something similar to MockitoAnnotations.injectMocks(). Okay so there is still some boilerplate code, but it is far less verbose.

@InjectMocks
private MyDelegate delegate;

@Mock
private MyListener listener1;

@Mock
private MyListener listener2;

@Before
public void setup() {
    MockitoCollections.initialise(this);
}

Ignoring a Mock when injecting into a Collection

Fields annotated with the @Mock annotation are considered for injection into Collection fields. It is possible to prevent a field annotated with @Mock being considered for this purpose using the @IgnoreForCollections annotation.

@Mock
@IgnoreForCollections
private MyListener listener1;

Verbatim Collections

The @CollectionOfMocks annotation can be used to create a Collection containing a specified number of mocks (by default this is one). In addition to creating a Collection of Mocks, the Collection will be considered for injection into Collection fields verbatim. These Collections will be injected when the generics are identical. This means Collection<InputStream> and Collection<FileInputStream> would not be considered equal nor would Collection<InputStream> and Set<InputStream> but List<InputStream> and List<InputStream> would.

@CollectionOfMocks(numberOfMocks = 2)
private Set<MyListener> listeners;

Collective Verification

To verify the same thing on a number of mocks we would typically make a call to the static Mockito.verify* methods for each mock. Mockito-Collections provides equivalent static methods allowing us to make verifications in a single step.

Imagine we have a Collection of Listeners and we want to verify that eventOccured(someEvent) was invoked once for every Listener. We would use the static MockitoCollections.collectiveVerify(Class, Collection) method.

MockitoCollections.collectiveVerify(Listener.class, listeners).eventOccured(someEvent);

Other collective verifications we can make using Mockito-Collections include verifying with a specified VerificationMode (for example times(int) and atLeastOnce()), verifying zero interactions, and verifying no more interactions.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages