我有以下Spring MVC控制器方法:
@RequestMapping(value = "/sendPasswordReset", method = RequestMethod.POST, produces = "text/html")
public String sendPasswordResetInformation(@ModelAttribute @Validated({ ValidationGroups.PasswordReset.class }) PasswordResetInfo passwordResetInfo,
BindingResult bindingResult, Model model, final RedirectAttributes redirectAttributes, Locale locale) throws InterruptedException, ExecutionException {
if (preferenceService.isEmailAvailable(passwordResetInfo.getEmail())) {
bindingResult.rejectValue("email", "controller.preference.email_not_in_system");
}
if (bindingResult.hasErrors()) {
model.addAttribute("passwordResetInfo", passwordResetInfo);
return "preference/sendPasswordReset";
}
redirectAttributes.addFlashAttribute("flashMessage", messageSource.getMessage("controller.preference.password_reset_info_sent", null, locale));
Future<Void> future = preferenceService.sendPasswordResetInfo(passwordResetInfo.getEmail());//.get();//TODO is ".get()" ugly?
future.get();//NPE HERE!!
return "redirect:/preference/sendPasswordReset";
}
以下是sendPasswordResetInfo
的实施:
@Async
@Override
public Future<Void> sendPasswordResetInfo(String email) {
Assert.hasText(email);
Member member = memberRepository.findByEmail(email);
try {
mailerService.doMailPasswordResetInfo(member);
return new AsyncResult<Void>(null);
} catch (MessagingException | MailSendException e) {
log.error("MessagingException | MailSendException", e);
throw new MailerException("MessagingException | MailSendException");
}
}
以下是我尝试集成测试控制器方法的方法:
@Test
public void sendPasswordResetShouldHaveNormalInteractions() throws Exception {
when(preferenceService.isEmailAvailable(anyString())).thenReturn(Boolean.FALSE);
mockMvc.perform(post("/preference/sendPasswordReset")//
.param("email", VALID_EMAIL))//
.andExpect(redirectedUrl("/preference/sendPasswordReset"))//
.andExpect(flash().attributeExists("flashMessage"))//
.andExpect(flash().attributeCount(1));
verify(preferenceService).sendPasswordResetInfo(eq(VALID_EMAIL));
reset(preferenceService);
}
我系统地在控制器方法中获取NullPointerException(在测试中),因为此处的future对象为null:
future.get()
然而,当我使用app(测试之外)时,控制器方法运行正常。
我尝试过如下使用同步任务执行程序(无济于事):
@Profile(Profiles.TEST)
@Configuration
@EnableAsync
public class FakeAsyncConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
SyncTaskExecutor taskExecutor = new SyncTaskExecutor();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
我的问题是:
Future
对象在集成测试期间始终为空并且