如何 运行 SpringBootTest 只有一个 bean 并包含 resilience4j 注释

How to run the SpringBootTest with only a single bean and with included resilience4j annotations

我想 运行 在 spring 启动应用程序中使用 resilience4j 注释方法对单个 bean 进行集成测试。我的目的是在不加载完整 spring 上下文的情况下测试 bean 方法调用的弹性。

设置如下:

依赖项包括以下内容:

io.github.resilience4j:resilience4j-spring-boot2
io.github.resilience4j:resilience4j-reactor
org.springframework.boot:spring-boot-starter-aop

resilience4j time limited spring bean with method to test:

@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()没有被接受,没有抛出超时异常,测试失败。

这里有人问过同样的问题:Testing SpringBoot with annotation-style Resilience4j但是没有解决方案。

我尝试了两种方法 - 实现 FooService 接口并直接使用具体的程序 class。结果一样。

如何在我的测试中考虑时间限制器注释?

编辑:我什至尝试使用以下设置进行普通 spring 测试(没有 spring 引导):

@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 {
    //...
}