When I enable Actuators in my Spring Boot application, my Junit tests failed with a NullPointer Exception. The actuators are working fine, and the tests were working fine before I added the actuator artifact in my pom.xml file.
Seems like the
@MockBean
MailSender mailSender;
is causing the problem
My pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
My Test:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
public class MailServiceTest extends CommonServiceTest {
@Autowired
MailService mailService;
@MockBean
MailSender mailSender;
private static final String TO = "[email protected]";
private static final String SUBJECT = "Subject";
private static final String TEXT = "Text";
private static final String TOKEN = "1234";
@Value("${app.email.from}")
private String fromEmail;
@Value("${app.email.support}")
private String supportEmail;
private ArgumentCaptor<SimpleMailMessage> simpleMailMessageCaptor;
@Override
public void initObjects() {
simpleMailMessageCaptor = ArgumentCaptor.forClass(SimpleMailMessage.class);
}
@Override
public void initMocks() {
}
@Test
public void sendMailTest() {
mailService.sendMail(TO, SUBJECT, TEXT);
verify(mailSender).send(simpleMailMessageCaptor.capture());
assertEquals(TO, simpleMailMessageCaptor.getValue().getTo()[0]);
assertEquals(SUBJECT, simpleMailMessageCaptor.getValue().getSubject());
assertEquals(fromEmail, simpleMailMessageCaptor.getValue().getFrom());
assertEquals(TEXT, simpleMailMessageCaptor.getValue().getText());
}
}
The error:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailHealthIndicator' defined in class path resource [org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthIndicator]: Factory method 'mailHealthIndicator' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1023)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:751)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 29 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthIndicator]: Factory method 'mailHealthIndicator' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 46 more
Caused by: java.lang.NullPointerException
at org.springframework.boot.actuate.autoconfigure.CompositeHealthIndicatorConfiguration.createHealthIndicator(CompositeHealthIndicatorConfiguration.java:42)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration.mailHealthIndicator(HealthIndicatorAutoConfiguration.java:334)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$$25b5897.CGLIB$mailHealthIndicator$0(<generated>)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$$25b5897$$FastClassBySpringCGLIB$$da72ce26.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$$25b5897.mailHealthIndicator(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 47 more
What value does Spring Boot Actuator provide? Spring Boot actuator allows you to monitor and interact with your application which is very important for a production application. Without a spring boot actuator, you need to build your own monitoring and interaction system using JMX.
Actuator is mainly used to expose operational information about the running application — health, metrics, info, dump, env, etc. It uses HTTP endpoints or JMX beans to enable us to interact with it. Once this dependency is on the classpath, several endpoints are available for us out of the box.
To enable Spring Boot actuator endpoints to your Spring Boot application, we need to add the Spring Boot Starter actuator dependency in our build configuration file. Maven users can add the below dependency in your pom. xml file. Gradle users can add the below dependency in your build.
The only solution I found was to add a properties in the test itself:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
// Otherwise I have a NullPointer, don't know why
@TestPropertySource(
properties = {"management.health.mail.enabled=false"})
public class MailServiceTest extends CommonServiceTest {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With