Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject multiple mocks of the same interface

The Java class (called ServiceCaller) I wish to test has this:

@Autowired @Qualifier(value="serviceA") SomeService serviceA;  @Autowired @Qualifier(value="serviceB") SomeService serviceB; 

(there's a doWork() method that will check a condition and call either A or B).

How do I inject a mock of each service into the appropriate variable?

My Junit has this:

@InjectMocks ServiceCaller classUnderTest = new ServiceCaller();  @Mock SomeService mockServiceA; @Mock SomeService mockServiceB; 

Yet when I run my tests to check that service A/B called under the correct condition, I get null pointers as the mock hasn't been injected.

Obviously its because of multiple dependencies on the same interface (SomeService). Is there a way to specify the qualifier when declaring the mock service? Or do I need to have setters for the dependencies and set the old fashioned way?

like image 795
shuttsy Avatar asked Jan 10 '14 20:01

shuttsy


People also ask

How do you inject an mock for an interface?

Here is what works: public class TestDo { @Mock private Do do; @Mock private ABC abc; @Before public void init() { MockitoAnnotations. initMocks(this); do. abc = abc; } @Test public void testDo() { when(do.

Can we use mock and InjectMocks together?

A mock doesn't have any real implementation. @InjectMocks would try to find and call setters for whatever mock objects have already been created and pass them in.

What is difference between @mock and @injectmock?

@InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock annotations into this instance. @Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class.

Can we create mock for interface?

mock() The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.


1 Answers

It should be enough to name your mocks serviceA and serviceB. From Mockito documentation:

Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.

In your example:

@InjectMocks ServiceCaller classUnderTest;  @Mock SomeService serviceA; @Mock SomeService serviceB; 

Note that it is not necessary to manually create class instance when using @InjectMocks.

Nevertheless I personally prefer injecting dependencies using constructor. It makes it easier to inject mocks in tests (just call a constructor with your mocks - without reflections tools or @InjectMocks (which is useful, but hides some aspects)). In addition using TDD it is clearly visible what dependencies are needed for the tested class and also IDE can generate your constructor stubs.

Spring Framework completely supports constructor injection:

@Bean public class ServiceCaller {     private final SomeService serviceA;     private final SomeService serviceB;      @Autowired     public ServiceCaller(@Qualifier("serviceA") SomeService serviceA,                          @Qualifier("serviceB") SomeService serviceB) { ... }      ... } 

This code can be tested with:

@Mock SomeService serviceA; @Mock SomeService serviceB;  //in a setup or test method ServiceCaller classUnderTest = new ServiceCaller(serviceA, serviceB);  
like image 71
Marcin Zajączkowski Avatar answered Sep 19 '22 09:09

Marcin Zajączkowski