When trying to write test case for applicationContext.getBean(classname). Getting null pointer exception. Below is the Java class
@Service
@Slf4j
public class MyClassName {
@Autowired
ServiceOne serviceOne;
@Autowired
ApplicationContext applicationContext;
public getCitizenData(String mobileNumber) {
CitizenDataService citizenDataService = applicationContext.getBean(CitizenDataService.class, mobileNumber);
log.info("Getting Data");
return citizenDataService.searchMethod(mobileNumber)
// While debugging test file citizenDataService is coming as Null Hence getting Null Pointer exception
.flatMap(.............
)
Test File
class MyClassNameTest {
private MyClassName mockMyClassName;
@BeforeEach
void setUp() {
mockMyClassName = new MyClassName();
mockMyClassName.serviceOne = mock(ServiceOne.class);
mockMyClassName.applicationContext = mock(ApplicationContext.class);
//mockMyClassName.applicationContext.getAutowireCapableBeanFactory();
}
@Test
void testGetCitizenData() {
// Setup
// Configure ApplicationContext.getBean(...).
final CitizenDataService citizenDataService = new CitizenDataService("mobileNumber");
when(mockMyClassName.applicationContext.getBean(CitizenDataService.class, "args"))
.thenReturn(citizenDataService);
final result = mockMyClassName.getCitizenData("mobileNumber");
// While debugging this citizenDataService is coming as Null Hence getting Null Pointer exception
How to write test case for this ?
CodePudding user response:
I think, application context is not set-up yet. The following code makes sure that the context has been set-up successfully.
If you use JUnit5, then automatic injection happens for application-context and still you can use '@Autowired' annotation to field inject that.
@SpringBootTest
class Test {
@Test
void contextLoads(ApplicationContext context) {
assertThat(context).isNotNull();
}
}
CodePudding user response:
It is because you stub the incorrect arguments on the getBean()
on the mocked ApplicationContext
. When a method on a mock is called but there are no matching stubbed arguments , it will return either null or an empty collection , or 0 for an int/Integer and false for a boolean/Boolean by default . So in you case NULL CitizenDataService
is returned.
Changing the following should fix your problem :
when(mockMyClassName.applicationContext.getBean(CitizenDataService.class, "mobileNumber"))
.thenReturn(citizenDataService);
Another way is not to mock the ApplicationContext
but use spring test to really start up the spring container which include the beans there are required for the test case :
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {MyClassName.class,ServiceOne.class,CitizenDataService.class})
public class MyClassNameTest {
@Autowired
private MyClassName myClassName
@Test
void testGetCitizenData() {
}
}
This will be slower than the plain Mockito approach because it needs more time to start up the spring container and also require you to manage what beans to be included in the context.
For me , I would refactor your class such that it does not require to autowire ApplicationContext
into it and then write a plain Mockito test. It is not a good practise to get the bean from the ApplicationContext
manually which will make your class coupled to the spring framework codes.