Java 如何在@Async void方法中断言异常?

Java 如何在@Async void方法中断言异常?,java,spring,spring-boot,spring-boot-test,spring-async,Java,Spring,Spring Boot,Spring Boot Test,Spring Async,我想断言应该在@Asyncvoid方法中引发的异常 以下操作失败,即使我已经添加了一个SyncTaskExecutorexplicit org.opentest4j.AssertionFailedError:预期将引发RuntimeException,但未引发任何内容 由于@Async方法由来自asyncExecutor的线程异步执行,并且由于RuntimeException而终止,这对主线程没有任何影响,因此实际上Main Test线程在触发异步调用后成功地与流的其余部分竞争一次。因此,我建议

我想断言应该在
@Async
void方法中引发的异常

以下操作失败,即使我已经添加了一个
SyncTaskExecutor
explicit

org.opentest4j.AssertionFailedError:预期将引发RuntimeException,但未引发任何内容


由于
@Async
方法由来自
asyncExecutor
的线程异步执行,并且由于
RuntimeException
而终止,这对主线程没有任何影响,因此实际上
Main Test
线程在触发异步调用后成功地与流的其余部分竞争一次。因此,我建议使用,始终保持异步进程的引用,即使它是必需的或不需要的,并且在测试用例中确实会有所帮助

@Service
@Async 
public class AsyncService {

    public CompletableFuture<Void> run() {
        //of course real world is more complex with multiple sub calls here
         throw new RuntimeException("junit test");
    }
 }

关于断言包装异常,您还可以参考另一个注意事项,因为
@Async
方法由
asynceducer
中的线程异步执行,并且由于
RuntimeException
而终止,这对主线程没有任何影响,实际上,
Main测试
线程触发异步调用后,会与流的其余部分成功竞争一次。因此,我建议使用,始终保持异步进程的引用,即使它是必需的或不需要的,并且在测试用例中确实会有所帮助

@Service
@Async 
public class AsyncService {

    public CompletableFuture<Void> run() {
        //of course real world is more complex with multiple sub calls here
         throw new RuntimeException("junit test");
    }
 }
关于断言包装异常,您还可以参考另一个注意事项

如何使用将为您的应用程序定义的异常

所以,基本上,当您执行抛出异常的方法时,您可以验证异常是在处理程序中处理的吗?只是一个想法,没有尝试过。

如何使用将为您的应用程序定义的工具


所以,基本上,当您执行抛出异常的方法时,您可以验证异常是在处理程序中处理的吗?只是一个想法,我没有尝试过。我面临着同样的问题

bilak的帖子提出了让我的自定义
AsyncUncaughtExceptionHandler
声明一个
@组件
注释的想法。 然后,在我的
AsyncConfigurer
自定义实现中,我注入了我的自定义
AsyncUncaughtExceptionHandler

在测试中,我在自定义的
AsyncUncaughtExceptionHandler
上使用了
@MockBean
注释,因此我能够验证调用
handleUncaughtException
时是否存在适当的异常

代码示例:

AsyncExceptionHandler

@Slf4j
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {

        log.error("Exception while executing with message: {} ", throwable.getMessage());
        log.error("Exception happen in {} method ", method.getName());
    }
}
自定义异步配置器

@Configuration
public class CustomAsyncConfigurer implements AsyncConfigurer {

    final private AsyncExceptionHandler asyncExceptionHandler;

    @Autowired
    public TaskExecutorConfiguration(AsyncExceptionHandler asyncExceptionHandler) {

        this.asyncExceptionHandler = asyncExceptionHandler;
    }

    @Override
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(50);
        executor.setThreadNamePrefix("AsyncThread::");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return asyncExceptionHandler;
    }
}
我的单元测试:

class FooServiceTest extends FooApplicationTests {

    @MockBean
    private AsyncExceptionHandler asyncExceptionHandler;
    @Autowired
    private FooService fooService;

    @Test
    void testCreateEnrollmentBioStoreException() throws Exception {

        fooService.doBar();

        ArgumentCaptor<FooException> argumentCaptor = ArgumentCaptor.forClass(FooException.class);
        verify(asyncExceptionHandler, times(1)).handleUncaughtException(argumentCaptor.capture(), any(), any());

        FooException exception = argumentCaptor.getValue();
        assertEquals("Foo error message", exception.getMessage());
    }
}
class FooServiceTest扩展了FooApplicationTests{
@蚕豆
私有AsyncExceptionHandler AsyncExceptionHandler;
@自动连线
私人餐饮服务;
@试验
void testCreateEnrollmentBioStoreException()引发异常{
fooService.doBar();
ArgumentCaptor ArgumentCaptor=ArgumentCaptor.forClass(FooException.class);
验证(asyncExceptionHandler,次(1)).handleUncaughtException(argumentCaptor.capture(),any(),any());
FooException=argumentCaptor.getValue();
assertEquals(“Foo错误消息”,exception.getMessage());
}
}

我不确定这是不是正确的方法,但我有一个void方法被转换成了async,所以我不想仅仅为了测试而更改返回值。

我也面临同样的问题

bilak的帖子提出了让我的自定义
AsyncUncaughtExceptionHandler
声明一个
@组件
注释的想法。 然后,在我的
AsyncConfigurer
自定义实现中,我注入了我的自定义
AsyncUncaughtExceptionHandler

在测试中,我在自定义的
AsyncUncaughtExceptionHandler
上使用了
@MockBean
注释,因此我能够验证调用
handleUncaughtException
时是否存在适当的异常

代码示例:

AsyncExceptionHandler

@Slf4j
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {

        log.error("Exception while executing with message: {} ", throwable.getMessage());
        log.error("Exception happen in {} method ", method.getName());
    }
}
自定义异步配置器

@Configuration
public class CustomAsyncConfigurer implements AsyncConfigurer {

    final private AsyncExceptionHandler asyncExceptionHandler;

    @Autowired
    public TaskExecutorConfiguration(AsyncExceptionHandler asyncExceptionHandler) {

        this.asyncExceptionHandler = asyncExceptionHandler;
    }

    @Override
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(50);
        executor.setThreadNamePrefix("AsyncThread::");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return asyncExceptionHandler;
    }
}
我的单元测试:

class FooServiceTest extends FooApplicationTests {

    @MockBean
    private AsyncExceptionHandler asyncExceptionHandler;
    @Autowired
    private FooService fooService;

    @Test
    void testCreateEnrollmentBioStoreException() throws Exception {

        fooService.doBar();

        ArgumentCaptor<FooException> argumentCaptor = ArgumentCaptor.forClass(FooException.class);
        verify(asyncExceptionHandler, times(1)).handleUncaughtException(argumentCaptor.capture(), any(), any());

        FooException exception = argumentCaptor.getValue();
        assertEquals("Foo error message", exception.getMessage());
    }
}
class FooServiceTest扩展了FooApplicationTests{
@蚕豆
私有AsyncExceptionHandler AsyncExceptionHandler;
@自动连线
私人餐饮服务;
@试验
void testCreateEnrollmentBioStoreException()引发异常{
fooService.doBar();
ArgumentCaptor ArgumentCaptor=ArgumentCaptor.forClass(FooException.class);
验证(asyncExceptionHandler,次(1)).handleUncaughtException(argumentCaptor.capture(),any(),any());
FooException=argumentCaptor.getValue();
assertEquals(“Foo错误消息”,exception.getMessage());
}
}

我不确定这是不是正确的方法,但我有一个void方法被转换为async,所以我不想仅仅为了测试而更改返回值。

这个方法完全失败。因为在junit测试中,
@Async
void方法仍然执行Async,即使提供了
SyncTaskExecutor
。所以,我仍然想测试这个异常……使用这个方法它完全失败了。因为在junit测试中,
@Async
void方法仍然执行Async,即使提供了
SyncTaskExecutor
。所以,我仍然想测试异常…但这需要更改应用程序代码,并使用返回值,仅用于测试,而无需实际使用。但我始终更喜欢保留子作业引用,而不是将其单独保留,因为这可能适用于web应用程序,但在正常的java世界中,子线程可能会在父线程终止时立即终止,但我认为你可以等待更好的答案@membersoundWell,但这需要更改带有返回值的应用程序代码,仅用于测试,而无需实际使用。但我始终更喜欢keep child作业引用,而不是将其单独保留,因为这可能在web应用程序中有效,但在普通java世界中,子线程可能会在父线程终止时立即终止,但我认为您可以等待bett