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



我想断言一个应该在@Asyncvoid 方法中抛出的异常。

即使我已经显式添加了SyncTaskExecutor,也失败了。

org.opentest4j.AssertionFailedError:预期抛出 RuntimeException,但未抛出任何内容。

@TestConfiguration
public class SyncTaskExecutorTestConfiguration {
@Bean
@Primary
public TaskExecutor asyncExecutor() {
return new SyncTaskExecutor();
}
}

@SpringBootTest
@Import(SyncTaskExecutorTestConfiguration.class)
public class MyTest {
@Test
public void test() {
assertThrows(RuntimeException.class, () -> service.run());
}   
}
@Service
@Async //also @EnableAsync existing on @Configuration class
public class AsyncService {
public void run() {
//of course real world is more complex with multiple sub calls here
throw new RuntimeException("junit test");
}
}

我面临着同样的问题。

Bilak的帖子给出了用@Component注释声明我的自定义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());
}
}

CustomAsyncConfigurer

@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());
}
}

我不确定这是否是正确的方法,但我有一个 void 方法变成了异步方法,所以我不想只为测试更改返回值。

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

@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从 ExecutionException 断言原因,因为get方法会抛出ExecutionException如果将来异常完成

CompletableFuture.allOf(wait);

还有一点说明,您可以参考链接来断言包装的异常

使用将为AsyncConfigurer定义的AsyncUncaughtExceptionHandler怎么样?

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

最新更新