Тестирование методов @ -синхронного возвращения в Spring @Async

У меня есть небольшая проблема с методами @Async которые возвращают void (или Unit , я пишу в Kotlin) в моем приложении Spring.

Я не знаю почему, но когда метод @Async возвращает void он просто не выполняется, или, по крайней мере, он не делает то, что должен. Нужно сказать, что в моих асинхронных методах я хочу отправить электронное письмо с помощью JavaMailSender , поэтому ничего особенного. Вот способ:

 @Async override fun sendEmail(locale: Locale, subject: String, message: String, to: String) { val msg = sender.createMimeMessage() println("1") val helper = MimeMessageHelper(msg, true, "utf-8") helper.setFrom("email@example.com") helper.setTo(to) println("2") helper.setSubject(getSubject(locale, null)) println("3") helper.setText(processTemplate(locale, null, null), true) println("4") sender.send(msg) println("5") } 

Но электронное письмо никогда не приходит, исключение не зарегистрировано (я запускаю тест testNG).

Когда я меняю подпись функции, чтобы она возвращала Future<String> и добавляла фиктивную возвратную строку в конец функции, а затем вызываю service.sendEmail(...).get() , тело метода магически выполняется и приходит электронная почта.

В моем классе @Configuration существует @EnableAsync . Я также реализовал AsyncConfigurer и предоставил собственный исполнитель и обработчик исключений, потому что я думал, что это могло быть что-то с моим определением bean-компонента исполнителя, но ничего не помогает.

Это сводит меня с ума, потому что я просто хочу тихо выполнить что-то в фоновом режиме, и это не сработает. Я молча говорю, что не хочу, чтобы меня беспокоили исключения, брошенные внутри.

У тебя есть идеи?

Обновление: так как @pleft посоветовал, я поместил некоторые отпечатки внутри своего метода. Теперь, когда я запускаю mvn clean test , я вижу, что 1,2,3 печатаются, но не каждый раз. Иногда печатались только 1 и 2. Я также помещаю печать в свой AsyncUncaughtExceptionHandler , но этот вызов не вызывается. Похоже, что фоновый поток убивается слишком рано или еще что-то.

Обновление 2:

Мой ServiceConfig:

 @Configuration @EnableScheduling @EnableAsync @ComponentScan class ServiceConfig : ApplicationContextAware, EnvironmentAware, AsyncConfigurer { override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { return AsyncUncaughtExceptionHandler { ex, method, params -> println("Exception thrown") } } override fun getAsyncExecutor(): Executor { val executor = ThreadPoolTaskExecutor() executor.corePoolSize = 2 executor.maxPoolSize = 2 executor.setQueueCapacity(500) executor.threadNamePrefix = "asyncThread" executor.initialize() return executor } } /// other beans definitions.. 

Может быть, это важно, может быть, нет, но я использую Thymeleaf в методе processTemplate.

Основываясь на разговоре в комментарии и моем собственном наблюдении (например, о том, чтобы немного поспать в методе тестирования), я выяснил причину. Это было причиной разрушения контекста весны внутри теста. Поскольку у меня был только один тест, запускающий этот асинхронный метод, поэтому сценарий заключался в том, что метод async возвращался немедленно, а также метод тестирования. Поскольку это был последний (и единственный) метод в моем тестовом наборе, тестовый Контекст был разрушен (а также все созданные им потоки).

Таким образом, разрешение состоит в том, чтобы либо поставить спит в тестах (очень уродливо), либо взглянуть на этот вопрос и получить вдохновение.