Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito - Injecting a List of mocks

I have the following code:

@Component  public class Wrapper {      @Resource      private List<Strategy> strategies;      public String getName(String id)     {     // the revelant part of this statement is that I would like to iterate over "strategies"         return strategies.stream()             .filter(strategy -> strategy.isApplicable(id))             .findFirst().get().getAmount(id);     }  } 

@Component  public class StrategyA implements Strategy{...}  @Component  public class StrategyB implements Strategy{...} 

I would like to create a Test for it using Mockito. I wrote the test as follows:

@InjectMocks private Wrapper testedObject = new Wrapper ();  // I was hoping that this list will contain both strategies: strategyA and strategyB @Mock private List<Strategy> strategies;  @Mock StrategyA strategyA;  @Mock StrategyB strategyB;  @Test public void shouldReturnNameForGivenId() {   // irrevelant code...     //when     testedObject.getName(ID); } 

I am getting NullPointerException on line:

filter(strategy -> strategy.isApplicable(id)) 

, which states that the "strategies" list is initialized but is empty. Is there any way Mohito will behave in the same wasy as Spring? Adding automatically all instances implementing interface "Strategy" to the list?

Btw I do not have any setters in Wrapper class and I would like to leave it in that way if possible.

like image 317
fascynacja Avatar asked Feb 20 '17 17:02

fascynacja


People also ask

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.

How do you inject mock in mock?

Mockito @InjectMocks annotations allow us to inject mocked dependencies in the annotated class mocked object. This is useful when we have external dependencies in the class we want to mock. We can specify the mock objects to be injected using @Mock or @Spy annotations.

What does InjectMocks annotation do?

@InjectMocks is the Mockito Annotation. It allows you to mark a field on which an injection is to be performed. Injection allows you to, Enable shorthand mock and spy injections.

What is the difference between @mock and @MockBean?

Main difference between @MockBean and @Mock annotation is that @MockBean creates mock and injects it into Application Context, while @Mock annotation only creates it, if you want to inject it, you can do it manually or with @InjectMocks annotation, however injection is being done to the class not whole Application ...


2 Answers

Annotate it with @Spy instead of @Mock. As Mockito cannot spy on an interface, use a concrete implementation, for example ArrayList. During test setup add the mocks to the List spy. This way you do not need to alter your test subject solely for test purposes.

@InjectMocks private Wrapper testedObject = new Wrapper();  @Spy private ArrayList<Strategy> mockedStrategies;  @Mock private StrategyA strategyA;  @Mock private StrategyB strategyB;  @Before public void setup() throws Exception {     mockedStrategies.add(strategyA);     mockedStrategies.add(strategyB); } 
like image 88
Erwin Dupont Avatar answered Sep 21 '22 16:09

Erwin Dupont


Mockito can not know that you want to put somthing in the List strategies.

You should rethink this an do something like this

@InjectMocks private Wrapper testedObject = new Wrapper ();  private List<Strategy> mockedStrategies;  @Mock StrategyA strategyA;  @Mock StrategyB strategyB;  @Before public void setup() throws Exception {     mockedStrategies = Arrays.asList(strategyA, strategyB);     wrapper.setStrategies(mockedStrategies); } 
like image 35
thopaw Avatar answered Sep 22 '22 16:09

thopaw