I have the following service class (Spring Boot):
@Service
public class MyService {
@Autowired
private DependedService dependedService;
@Transactional
public boolean saveMyDetails(Integer id, List<> myList) {
dependedService.saveSomething(id, myList);
...
return true;
}
I've implemented a test method to assert that the service method return true. please note that the requirement is to ignore the call to the depended service:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceTests {
@Mock
private MyService myService = new MyService ();
@MockBean
private DependedService dependedService;
@BeforeEach
public void init() {
...
...
}
@Test
public void testSaveMyDetails() {
...
...
doNothing().when(dependedService).saveSomething(Mockito.anyInt(), Mockito.anyList());
when(myService.saveMyDetails(someId, someList)).thenCallRealMethod();
assertEquals(true, myService.saveMyDetails(someId, someList));
}
When running the test it seems that the depended service is not initialized correctly and I'm not sure what should it annotated with in the test class (in the service is a Autowired) the exception is thrown at the service layer:
java.lang.NullPointerException: Cannot invoke ... because "<local4>.dependedService" is null
You should not instantiate MyService
on your own since you are using Spring framework for testing. You are not allowing the framework to do its work.
There are at least two options:
MyService
bean should be a bean (not a mock), just remove the instantiation and add @Autowired
annotation to let Spring inject the mocked bean into the service. In that case, since your MyService bean is a bean that you are testing and filling with mocks, MyService bean will not be a mock, so you don't have to call thenCallRealMethod.@RunWith(SpringRunner.class)
@SpringBootTest
class MyServiceTest {
@Autowired
private MyService myService;
@MockBean
private DependedService dependedService;
@BeforeEach
public void init() {
}
@Test
void testSaveMyDetails() {
doNothing().when(dependedService).saveSomething(Mockito.anyInt(), Mockito.anyList());
myService.saveMyDetails(someId, someList);
assertTrue(myService.saveMyDetails(someId, someList));
}
}
@SpyBean
annotation. Just remove the instantiation and add the annotation.@RunWith(SpringRunner.class)
@SpringBootTest
class MyServiceTest {
@SpyBean
private MyService myService;
@MockBean
private DependedService dependedService;
@BeforeEach
public void init() {
// I added this just to show that you have an
// ability to manage the service bean behaviour.
// You can remove this.
when(myService.saveMyDetails(someOtherId, someOtherList))
.thenThrow(new IllegalArgumentException());
}
@Test
void testSaveMyDetails() {
doNothing().when(dependedService).saveSomething(Mockito.anyInt(), Mockito.anyList());
myService.saveMyDetails(someId, someList);
assertTrue(myService.saveMyDetails(someId, someList));
}
}