发布集成测试Spring MVC控制器方法,该方法调用异步Spring服务方法

时间:2014-06-21 20:53:39

标签: spring spring-mvc asynchronous future spring-mvc-test

我有以下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对象在集成测试期间始终为空并且
  • 如何在集成测试期间确保它不为空?

0 个答案:

没有答案