I am writing a happy path unit test for method_a which calling a private method method_b.
The service is based on springboot framework and java8.
Junit5 and Mockito are used for unit test.
Following are the basic code structure, sorry can't show the original code.
public class SomeClass {
public boolean method_a(obj obj_data) {
...
Optional<String> str;
str = method_b(str_1);
if(!str.isPresent()) {
return false;
}
...
return true;
}
private Optional<String> method_b(String str) {
...
try {
...
return Optional.of(thirdPartCtrl.method_c(val_1));
}
cathch (Exception exception) {
...
return Optional.empty();
}
}
}
Following are the unit test code:
approach_1:
@Test
void test method_a() {
...
when(ReflectionTestUtils.invokeMethod(SomeClassMock,"method_b", "str_input")).thenReturn(Optional.of("validData"));
...
assertTrue(SomeClass.method_a(val));
}
approach_2:
@Test
void test method_a() {
...
doReturn(Optional.of("validData")).when(ReflectionTestUtils.invokeMethod(SomeClassMock,"method_b", "str_input"));
...
assertTrue(SomeClass.method_a(val));
}
I noticed that when I run the unit test, java.lang.NullPointerException was always generated from line return Optional.of(thirdPartCtrl.method_c(val_1)); in the private method method_b
Current issue is:
If I do not use ReflectionTestUtils.invokeMethod to invoke the private method_b, SomeClass.method_a(val) will always return false.
By using
when(ReflectionTestUtils.invokeMethod(SomeClassMock,"method_b", "str_input")).thenReturn(Optional.of("validData"));
I will get error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Optional cannot be returned by convert()
convert() should return NotificationRequestDetails
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
If I use
doReturn(Optional.of("validData")).when(ReflectionTestUtils.invokeMethod(SomeClassMock,"method_b", "str_input"));
will get error:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
What did I do wrong with ReflectionTestUtils.invokeMethod?
Is there a better way to mock the private method to return a valid value?
Any suggestion are appreciated! Thank you!