使用 Spring Boot Actuator 的 Junit 测试给出异常
Junit Tests with Spring Boot Actuator gives Exception
当我在我的 Spring 引导应用程序中启用执行器时,我的 Junit 测试因 NullPointer 异常而失败。
执行器工作正常,在我将执行器工件添加到我的 pom.xml 文件之前,测试工作正常。
好像是
@MockBean
MailSender mailSender;
导致问题
我的 pom.xml 文件:
<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>
我的测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
public class MailServiceTest extends CommonServiceTest {
@Autowired
MailService mailService;
@MockBean
MailSender mailSender;
private static final String TO = "user@test.com";
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());
}
}
错误:
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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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.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$b5897.CGLIB$mailHealthIndicator[=14=](<generated>)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$b5897$$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$b5897.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
我找到的唯一解决方案是在测试本身中添加一个属性:
@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 {
这通常是有一些代理 class 包裹您的 JavaMailSenderImpl
的症状。
检查您是否在依赖项中使用接口,例如JavaMailSender
你会看到 HealthIndicatorAutoConfiguration.MailHealthIndicatorConfiguration
找到并填充 mailSenders
:
public MailHealthIndicatorConfiguration(
ObjectProvider<Map<String, JavaMailSenderImpl>> mailSenders) {
this.mailSenders = mailSenders.getIfAvailable();
}
除了 Leamas 我想补充的建议之外,如果您使用 @MockBean
来模拟 MailSender
,则可能会发生这种情况,在这种情况下,似乎MockedMailSender
未被 MailHealthIndicator 找到。我就是这种情况,并且使用 Leamas 的建议禁用 MailHealthIndicator 有效。
您可以在应用程序中添加以下属性-test.properties,它将禁用默认配置
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.enabled=false
当我在我的 Spring 引导应用程序中启用执行器时,我的 Junit 测试因 NullPointer 异常而失败。 执行器工作正常,在我将执行器工件添加到我的 pom.xml 文件之前,测试工作正常。
好像是
@MockBean
MailSender mailSender;
导致问题
我的 pom.xml 文件:
<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>
我的测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
public class MailServiceTest extends CommonServiceTest {
@Autowired
MailService mailService;
@MockBean
MailSender mailSender;
private static final String TO = "user@test.com";
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());
}
}
错误:
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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.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.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$b5897.CGLIB$mailHealthIndicator[=14=](<generated>)
at org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration$MailHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$b5897$$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$b5897.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
我找到的唯一解决方案是在测试本身中添加一个属性:
@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 {
这通常是有一些代理 class 包裹您的 JavaMailSenderImpl
的症状。
检查您是否在依赖项中使用接口,例如JavaMailSender
你会看到 HealthIndicatorAutoConfiguration.MailHealthIndicatorConfiguration
找到并填充 mailSenders
:
public MailHealthIndicatorConfiguration(
ObjectProvider<Map<String, JavaMailSenderImpl>> mailSenders) {
this.mailSenders = mailSenders.getIfAvailable();
}
除了 Leamas 我想补充的建议之外,如果您使用 @MockBean
来模拟 MailSender
,则可能会发生这种情况,在这种情况下,似乎MockedMailSender
未被 MailHealthIndicator 找到。我就是这种情况,并且使用 Leamas 的建议禁用 MailHealthIndicator 有效。
您可以在应用程序中添加以下属性-test.properties,它将禁用默认配置
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.enabled=false