我想在spring引导应用程序中运行一个带有resilience4j注释方法的单个bean的集成测试。我的意图是测试bean方法调用的弹性,同时不加载完整的spring上下文。
设置如下:
依赖项包括以下内容:
io.github.resilience4j:resilience4j-spring-boot2
io.github.resilience4j:resilience4j-reactor
org.springframework.boot:spring-boot-starter-aop
弹性4j时限弹簧豆的试验方法:
@Service
public class FooService {
@TimeLimiter(name = "fooTimeLimiter")
public FooResponse foo() {
//entertain operation that might timeout
}
}
配置:
resilience4j.timelimiter.instances.fooTimeLimiter.timeoutDuration=1s
测试:
@SpringBootTest
@ContextConfiguration(classes = FooService.class)
public class FooServiceIT {
@Autowired
private FooService service;
@MockBean
private Bar bar;
@Test
void foo_timeout() {
//setup mocks so the operation delays the output and shall end up with timeout
Assertions.assertThrows(TimeoutException.class, () -> service.foo());
}
}
但是,TimeLimiterAdvice.proceed((不被接受,不会引发超时异常,并且测试失败。
这里也提出了同样的问题:使用注释样式Resilience4j测试SpringBoot,但没有解决方案。
我尝试了两种方法——直接使用具体类实现FooService接口和程序。同样的结果。
我如何才能在测试中考虑到时间限制注释?
编辑:我甚至尝试了以下设置的普通弹簧测试(没有弹簧引导(:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class FooServiceIT {
@Configuration
@Import({TimeLimiterConfiguration.class, FallbackConfiguration.class, SpelResolverConfiguration.class})
static class ContextConfiguration {
@Bean
public FooService fooService() {
//prepare bean;
}
@Bean
public TimeLimiterConfigurationProperties timeLimiterConfigurationProperties() {
return new TimeLimiterConfigurationProperties();
}
}
@Autowired
private FooService service;
//tests...
}
相同的结果(即没有超时异常(。
在处理SpringBootTest
和@CircuitBreaker
时,将@EnableAspectJAutoProxy
注释添加到测试中就足够了。在这一变化之后,CircuitBreakerAspect
被接受,并且测试表现如预期。
为了使@TimeLimiter
按预期工作,还需要向该方法添加@Bulkhead
注释。
更新后的方法如下:
@Bulkhead(name = "fooBulkhead", type = Type.THREADPOOL)
@CircuitBreaker(
name = "fooCircuitBreaker",
fallbackMethod = "fooFallback"
)
@TimeLimiter(
name = "fooTimeLimiter"
)
public CompletableFuture<FooResponse> foo() {
//...
}
以及测试:
@SpringBootTest(classes = FooService.class)
@EnableAspectJAutoProxy
@Import(value = {CircuitBreakerAutoConfiguration.class, TimeLimiterAutoConfiguration.class, BulkheadAutoConfiguration.class})
public class FooServiceIT {
//...
}