Reputation: 9
While writing a testCase for Controller class,The private method that is getServiceContext(). has different object because one we are passing serviceContext from testclass and other object inside the controller class itself call itself.Due to this Foo object is null. how to resolve this.
public class Controller {
@Refernce
private FooService fooService;
public CustomData getDetails(String id){
Foo foo = fooService.getFoo(id ,**getServiceContext()**);
//getServiceContext() is different object
System.out.println("foo data>>>> "+foo); // **Throwing null pointer exceptions**
CustomData customData = new CustomData();
customData.setStudentName(foo.getName);
customData.setStudentName(foo.getId);
...
...
...
return customData;
}
private ServiceContext getServiceContext() {
ServiceContext serviceContext = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
retrn serviceContext;
}
}
public class ControllerTest {
@InjectMocks
private Controller controller;
@Mock
private FooService fooService;
private Foo foo;
@BeforeEach
public void setUp() throws PortalException {
foo = mock(Foo.class);
}
@Test
public void getDetailsTest() throws Exception {
ServiceContext **serviceContext** = new ServiceContext();
serviceContext.setCompanyId(context..);
serviceContext.setUserId(context..);
...
....
Mockito.when(fooService.getFoo("testId",serviceContext)).thenReturn(foo);
System.out.println("Service context>>>> "+**serviceContext**); // different serviceContext object
CustomData customData = controller.getDetails("testId");
Assertions.assertThat(ss).isNotNull();
}
}
Upvotes: 1
Views: 1223
Reputation: 2900
There are multiple ways to do that.
First, we can mock with anyOf(Type.class)
, that will actually match object type rather than value.
Mockito
.when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
.thenReturn(foo);
this will work as expected and return the desired value.
Additionally, if you want to check with what data serviceContext
object is being passed as arg in service method, (as we just checked object type rather than value), We can use ArgumentCaptor
for that.
It basically captures argument data which is being passed in the method call.
let's create ArgumentCaptor for service context
@Mock
private FooService fooService;
@Captor
private ArgumentCaptor<ServiceContext> captor;
Now, let's capture the argument during verification.
Mockito.verify(fooService).getFoo(Mockit.eq("testId"), captor.capture());
Assertions.assertEquals("value of x in context", captor.getValue().getX());
Basically here, captor.getValue()
returns service context object which is being passed. So, you can verify all data you want to validate in that object.
Alternate, Approach would be Spy
which will basically spy on the class under test and you can control the behavior of private methods in test class itself.
To do that, we need to add @Spy
annotation along with @InjectMocks
on test class.
@Spy
@InjectMocks
private Controller controller;
Now, you can mock the private method and return the expected value.
Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
and use that object for mocking fooService
.
Mockito.verify(fooService).getFoo("testId", serviceContextValue);
But when using Spy
, don't forget to write unit test for private method as it's mocked, it's business logic will not be tested by above test cases. that's a reason, it's not recommended way.
I would suggest using ArgumentCaptor
approach.
Upvotes: 1