如何为使用@Circuitbreaker 注释的方法创建单元测试

How to create unit tests for methods annotated with @Circuitbreaker

我在我的项目中使用 Spring Boot2 启动程序 (https://resilience4j.readme.io/docs/getting-started-3) 实现了 resilience4j。

我用 @CircuitBreaker 注释了一个方法,该方法使用 http 客户端调用外部服务,并且断路器工作正常 - 包括其回退。

我想为它添加单元测试,但是当我 运行 一个试图模拟回退的测试时,没有任何反应 - 异常被抛出但没有被断路器机制处理。

我找到了一些使用其指标的示例,但它对我的情况没有用。

有什么想法吗?

这是我的客户的片段:

@CircuitBreaker(name = "MY_CICUIT_BREAKER", fallbackMethod = "fallback")
    public ResponseEntity<String> search(String value) {

        ResponseEntity<String> responseEntity = restTemplate.exchange(
                searchURL,
                HttpMethod.GET,
                new HttpEntity(new HttpHeaders()),
                String.class,
                value);
    }

public ResponseEntity<String> fallback(String value, ResourceAccessException ex) {
        return "fallback executed";
    }

您不应该在单元测试中测试@CircuitBreaker,因为它涉及多个class。而是使用集成测试。

作为andres and pvpkiranmentioned/explained,我不得不添加一个集成测试。

您基本上可以将 @SpringBootTest 注释添加到您的测试 class,它将 bootstrap 一个带有 spring 上下文的容器。

我还自动连接了 CircuitBreakerRegistry,以便在每次测试前重置断路器,这样我就可以保证测试干净。对于 mocking/spying/verifying,我使用了 spring 启动测试启动器 (spring-boot-starter-test) 中的 Mockito。

以下是我设法测试后备方法的方法:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class)
public class RestClientIntegrationTest {

    private final String SEARCH_VALUE = "1234567890";

    @MockBean( name = "myRealRestTemplateName")
    private RestTemplate restTemplate;

    @SpyBean
    private MyRestClient client;

    @Autowired
    private CircuitBreakerRegistry circuitBreakerRegistry;

    @BeforeEach
    public void setUp() {
        circuitBreakerRegistry.circuitBreaker("MY_CIRCUIT_BREAKER_NAME").reset();
    }

    @Test
    public void should_search_and_fallback_when_ResourceAccessException_is_thrown() {
        // prepare
        when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class), eq(SEARCH_VALUE)))
                .thenThrow(ResourceAccessException.class);

        String expectedResult = "expected result when fallback is called";

        // action
        String actualResult = client.search(SEARCH_VALUE);

        // assertion
        verify(client).fallback(eq(SEARCH_VALUE), any(ResourceAccessException.class));
        assertThat(actualResult, is(expectedResult));
    }

}

我希望没有编译错误,因为我不得不删除一些不相关的东西。