How to stub a method of an class annotated with #InjectMocks? - java

Below MyDictionary.get method uses the injected map by calling map.get.
Just of curiosity I stubbed the MyDictionary.get method, like I always do with mocks and spies, so I overwrite the injection.
But this only works when MyDictionary.get indeed calls map.get. If map.get returns some string (the empty string here), the stub Mockito.when does not work. The behavior is as if it is not there. In the assert line, dictionary.get("key") equals the empty string. This is what I do not understand.
#RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
#Mock
Map<String, String>map;
#InjectMocks
MyDictionary dictionary;
#Test
public void testMyDictionary(){
Mockito.when(dictionary.get("key")).thenReturn("value");
Assert.assertEquals("value", dictionary.get("key"));
}
private static class MyDictionary{
private Map<String, String> map;
public String get(String key){
return map.get(key);
// or,
return "";
}
}
}

I am really surprised that you do not get a MissingMethodInvocationException which is thrown when you try to stub a method of an object not being a #Mock or a #Spy.
The dictionary instance is just a regular instance of a class here not proxied by Mockito (because of the fact that only #InjectMocks annotation is used).
Another surprise is that you do not get a null when the map.get is triggered as default return value for a String returning method is null.
Anyway..
If you want to stub methods of the `dictionary' instance you have to configure your test class as follows:
#InjectMocks
#Spy
MyDictionary dictionary;
#Test
public void testMyDictionary(){
doReturn("value").when(dictionary).get("key);
Assert.assertEquals("value", dictionary.get("key"));
}

Related

Mockito, how to verify if the method of the tested class was called?

I want to check if toDishResponseDTO was called during a method execution. But it's not possible since this is a method of the class being tested. How can this be done?
Class
#ExtendWith(MockitoExtension.class)
class DishServiceTest {
#Mock
DishRepository dishRepository;
#Mock
RestaurantRepository restaurantRepository;
#Autowired
#InjectMocks
DishService dishService;
Method under test
public List<DishResponseDTO> getAll() {
List<Dish> dishlsit = dishRepository.findAll();
return dishlsit.stream()
.map(this::toDishResponseDTO)
.collect(Collectors.toList());
}
Test
#Test
void shouldCallFindAllReturnDto_whenV() {
Mockito.when(dishRepository.findAll()).thenReturn(TestData.ENTITY_DISH);
dishService.getAll();
Mockito.verify(dishRepository, times(1)).findAll();
Mockito.verify(dishService times(6)).toDishResponseDTO(any()); // compile error, because verify can be called only on mocks
}
You won't be able to use Mockito to verify that method is called, but you can verify the output from the getAll() method given that you've mocked out the response to dishRepository.findAll(). So, in effect, just add some assertions after your verify calls that match your expected data with the actual data, I assume that this::toDishResponseDTO just return a Dish.
#Test
void shouldCallFindAllReturnDto_whenV() {
Mockito.when(dishRepository.findAll()).thenReturn(TestData.ENTITY_DISH);
List<Dish> dishes = dishService.getAll();
Mockito.verify(dishRepository, times(1)).findAll();
assertThat(dishes, is(notNullValue());
assertThat(dishes.get(0).getSomeField, is(equalTo("someValue")));
}

Mocking a ListState in Apache Flink 1.4

I am writing some test code for a processElement function in Apache Flink 1.4:
public class ProcessFunctionClass {
public void processElement(Tuple2<String, String> tuple2, Context context, Collector<Tuple2<String, String>> collector) {
// if the state is empty, start a timer
if (listState.get().iterator().hasNext() == false)
context.timerService().registerEventTimeTimer(1000);
listState.add("someStringToBeStored");
// ...
}
}
public class ProcessFunctionClassTest {
private ProcessFunctionClass processFunctionClass;
#Mock
private ListState<String> listState;
#Before
public void setUp() throws Exception {
processFunctionClass = new ProcessFunctionClass();
}
#Test
public void testProcessElement() {
ListState mockListState = mock(ListState.class);
Iterable mockIterable = mock(Iterable.class);
Iterator mockIterator = mock(Iterator.class);
MockitoAnnotations.initMocks(this);
when(tDPListState.get()).thenReturn(mockIterable);
when(tDPListState.get().iterator()).thenReturn(mockIterator);
when(tDPListState.get().iterator().hasNext()).thenReturn(false);
processFunctionClass.processElement(tuple2, context, collector);
// verify(...)
}
}
When I debug using my IDE, just before I step into the processElement() method, listState is not null and appears to have been mocked successfully, but as soon as I get to listState.get().iterator().hasNext(), listState is null and I get a NullPointerException. What am I doing wrong here?
In ProcessFunctionClass you have a private listState variable.
In your test you create a completely unrelated mockListState variable and set some expectations on it.
For your test to work, you must provide a way (constructor or setter) to set ProcessFunctionClass.listState to desired value (your mocked list state)
On top of that, MockitoAnnotations.initMocks(this); seems to do nothing in your example: you haven't shown us any fields annotated with #Mock or #InjectMocks
Update
You are misusing #Mock annotation.
You should place it in the test class, not in class under test.
When placed in the test class, after a call to initMocks, the filed will be initialized with a mock of an appropriate type.
What you should fo instead:
remove MockitoAnnotations.initMocks(this);, you are creating all the mocks manually.
add a constructor in ProcessFunctionClass
public ProcessFunctionClass(ListState<String> listState) {
this.listState = listState
}
use this constructor in your test
var mockListState = mock(ListState.class);
var processFunctionClass = new ProcessFunctionClass();

Mockito incorrectly injecting string value

I have created an object in my test class, testObj, and mockDao is a dao object that I have mocked.
Function to test is something like:
MyDao myDao;
String myFunc(String param1, String param2) {
MyObj realObj = new MyObj("param1", "param2");
return myDao.someFunction(realObj);
}
UnitTest class something like:
#Mock
MyDao mockDao;
#InjectMock
MyComponent component;
MyObj testObj = new MyObj("param1", "param2");
#Test
public void test() {
Mockito.when(mockDao.someFunction(testObj)).thenReturn(“123”);
String returnedValue = component.myFunc("param1","param2");
Assert.assertEquals(returnedValue, "123");
}
this should not inject “123” in my actual class, since the object that is created in actual class (realObj) is different from the testObj.
However, this is injecting "123" and my test is passing. While ideally it should fail.
How is it possible that this injection is happening?
You're not using any argument matcher in your mock setting, in this case Mockito should use the default one: any(), which does not any checks about how method has been invoked (it returns true in every case).
Try to: Mockito.when(mockDao.someFunction(Mockito.eq(testObj)).thenReturn(“123”). In this case Mockito is going to use the equals method of the object, in your case is the object reference.
I suggest you if you need somethig like "Anything does not match the following", try to look at AdditionalMatchers of Mockito

Mockito default behaviour and custom behaviour with methods with identical return types

Supossing I have the following code to test UserController by mocking UserService (where UserController has a reference to UserService):
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
...
public class UserControllerTest {
private final List<User> users1 = new ArrayList<>();
private final List<User> users2 = new ArrayList<>();
#Before
public void initUsers() {
User user = new User();
user.setId(1L);
users1.add(user);
User user = new User();
user.setId(2L);
users2.add(user);
}
#Test
public void testFindAlls() throws Exception {
UserService userService = mock(UserService.class); //line1
when(userService.findAll1()).thenReturn(users1); //line2
when(userService.findAll2()).thenReturn(users2); //line3
UserController userController = new UserController();
ReflectionTestUtils.setField(userController, "userService", userService);
List<User> users3 = userController.findAll1(); //line4
List<User> users4 = userController.findAll2(); //line5
...
}
}
I have the following doubts:
When the line1 is reached, what would be the default behaviour for userService.findAll1() and userService.findAll2()?
When the line3 is reached, as userService.findAll1() and userService.findAll2() return the same result type (List<User>). Will the line3 override the behaviour defined in line2? I mean, will userService.findAll1() return users2 instead of users1?
I mean, the when method signature is public static <T> OngoingStubbing<T> when(T methodCall) so T in the example would be an element of type List<User> with the value probably to null. So, how the when method is able to determine that different calls are passed as arguments?
1.
When you mock something all methods - that have a return type - would just return null by default (or equivalents in case of primitives). Since the mock has no implementation on its own, a call to the method is doing nothing (basically it handles like an empty method).
2.
Why would that be? You map different return values to different methods, there is no possibility of overriding something.
Edit3:
I just removed my previous try to expalin this. The content of the link is better than anything I can come up with. So it's not easy to understand.
How does mockito when() invocation work?
On another note:
You might not need to use Reflections to put the mock into your object. Check out #InjectMocks & #Mock. So wheter you can use them (or how to use them) depends on your JUnit and Mockito version.
(How to use Mockito with JUnit5)

Can't access methods of #Injectable inside Expectations() of Jmockit?

I define an #Injectable in my test class as below
#Injectable
IndividualPaymentServiceLocal individualPaymentService;
and then initialize this reference inside #Before method of Junit as
individualPaymentService = new MockUp<IndividualPaymentServiceLocal>() {
#Mock
public void $init() {
}
#Mock
public List<IndividualPayment> search(#Nullable String clinicId, #NotNull TimeWindow timeWindow, #Nullable IndividualPaymentFetchConfig fetchConfig) {
return paymentsList_1;
}
}.getMockInstance();
IndividualPaymentServiceLocal is a local EJB interface and has a
search() method that I mock as shown above to return an ArrayList
paymentsList_1. Now in my one of #Test methods, I wish to return a
different ArrayList so I try to use Jmockit's Expectations like below
new Expectations(){
individualPaymentService.search(anyString,any,any); result=paymentsList_2;
};
but search method is not resolved on individualPaymentService reference so code doesn't compile. Outside Expectations, its resolved. Am I missing something? I am using IntelliJ Idea. Please suggest.

Categories