我在我的一个服务方法中调用@Async
方法,现在我试图模拟当@Async
方法在后台抛出异常时的情况,以Assert调用者方法继续正常执行,尽管异步抛出异常。
最初在测试中,我尝试模拟抛出的异常:
when(myAsyncServiceMock.myAsyncMethod(...some arguments...).thenThrow(new RuntimeException("failed to complete asynchronous method"));
但在这种情况下,调用方方法的行为就好像运行时异常是在主线程中抛出的,而不是异步的。
Mockito是否有办法指定thenThrow(...)
中的异常应该异步抛出,而不是在主线程中抛出?
UPD。这是一个类,在这个类中调用了autowired bean的方法:
@Log4j2
@Service
@Setter
@ConfigurationProperties(prefix = "spring.profiles")
public class MyService {
@Autowired private MyAsyncUtil asyncUtil;
public void myMethod1() {
myMethod2();
}
public void myMethod2() {
asyncUtil.myAsyncMethod();
}
}
这是MyAsyncUtil
类,方法注解为@Async
:
@Component
@Log4j2
public class MyAsyncUtil {
@Async
public Void myAsyncMethod() {
// do something
}
}
1条答案
按热度按时间5q4ezhmt1#
@Async
是一个Spring框架注解-如果方法调用在Spring上下文内(Spring beans之间)执行,则该方法可能会被拦截并在与原始调用者线程不同的线程上运行。如果在Spring上下文之外调用该方法,则@Async
注解将被忽略,并且该方法将在与调用者相同的线程上执行。你可以编写一个包含Spring的测试,并像这样验证行为:
您将在控制台中看到,异常实际上被抛出并记录,但原始调用不会因为异常而中断,因为它在另一个线程上运行。如果你愿意,你也可以验证例如是否调用了
AsyncUncaughtExceptionHandler
(使用Mockito.verify
方法),但是在这种情况下,你必须记住调用是在与主线程不同的线程上执行的,所以可能需要使用Awaitility这样的库来避免重复测试(主线程可能在重复测试线程之前完成运行)。注意:assertThatNoException
是AssertJ library的一个方法。在测试中模拟异步执行的另一种方法可以简单地自己创建新线程,模仿Spring行为:
这种方法的缺点是
@Async
注解并不是工作所必需的--如果将来将其删除,测试仍然可以通过。我建议不要使用这种方法,因为它只是测试在不同线程中抛出的异常不会被主线程捕获的事实,这是Java的真理。尽管如此,这些测试仍然有助于理解Spring在“幕后”是如何工作的。我已经准备好了a GitHub repository-我验证了这两个测试,他们通过。