Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create unit tests for methods annotated with @Circuitbreaker

Tags:

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";
    }
like image 526
Eduardo Lima Avatar asked Mar 30 '20 13:03

Eduardo Lima


People also ask

Is SpringBootTest a unit test?

Well, this is not a unit test. When we use the @SpringBootTest annotation, Spring loads up an application context for the test. In practice, we have started the whole application only to autowire the OrderService into the test.

What is the easiest method to write a unit test in spring?

Spring Boot simplifies unit testing with SpringRunner . It is also easier to write unit tests for REST Controller with MockMVC . For writing a unit test, Spring Boot Starter Test dependency should be added to your build configuration file (pom.


2 Answers

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.

like image 148
Eduardo Lima Avatar answered Oct 02 '22 15:10

Eduardo Lima


You shouldn't test @CircuitBreaker in a unit test as it involves more than one class. Rather use an integration test.

like image 28
Andres Avatar answered Oct 02 '22 16:10

Andres