Search code examples
javaspring-bootunit-testingaopresilience4j

How to create unit tests for methods annotated with @Circuitbreaker


I implemented resilience4j in my project using the Spring Boot2 starter (https://resilience4j.readme.io/docs/getting-started-3).

I annotated a method with @CircuitBreaker that uses http client for calling an external service and the circuit breaker is working fine - including its fallback.

I'd like to add unit tests for it but when I run a test trying to simulate the fallback, nothing happens - the exception is thrown but is not handled by the circuit breaker mechanism.

I've found some examples using its metrics but it is not useful in my case.

Any thoughts?

Here is a snippet of my client:

@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";
    }

Solution

  • As andres and pvpkiran mentioned/explained, I had to add a integration test.

    You can achieve that basically adding @SpringBootTest annotation to your test class, it will bootstrap a container with spring context on it.

    I also autowired CircuitBreakerRegistry in order to reset the circuit breaker before each test so I could guarantee a clean test. For mocking/spying/verifying I used Mockito from spring boot test starter (spring-boot-starter-test).

    Here is how I managed to test the fallbacks methods:

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

    I hope there is no compilation error since I had to remove some non-relevant stuff.