> For the complete documentation index, see [llms.txt](https://www.pranaypourkar.co.in/the-programmers-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.pranaypourkar.co.in/the-programmers-guide/software-testing/java-test-framework/spring-test/mocking-in-spring-tests/verifying-retries-with-retryable.md).

# Verifying retries with @Retryable

## About

In Spring Boot applications, the `@Retryable` annotation (from **Spring Retry**) allows methods to be retried automatically upon specified exceptions. This is especially useful for transient failures such as network issues, service timeouts, or temporary unavailability of external systems.

During integration testing, it’s often necessary to verify that the retry mechanism works as expected—specifically, that the method is invoked the correct number of times before ultimately failing or succeeding.

## Example

### Actual Source Code

Enable Spring Retry in our main class or any configuration class.

```java
@SpringBootApplication
@EnableRetry
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
```

Create a Service with `@Retryable`

```java
@Service
public class PaymentService {

    @Retryable(value = SomeRetryableException.class, maxAttempts = 3)
    public void abc() {
        throw new SomeRetryableException("Simulated failure");
    }
}
```

Use the Service in a Controller

```java
@RestController
@RequestMapping("/api/v1/payment")
public class PaymentController {

    @Autowired
    private PaymentService paymentService;

    @PostMapping("/notification")
    public ResponseEntity<Void> notifyPayment() {
        paymentService.abc();
        return ResponseEntity.ok().build();
    }
}
```

### Test Class

Write Integration Test to Verify Retries

```java
@SpringBootTest
@AutoConfigureMockMvc
public class PaymentNotificationIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @SpyBean
    private PaymentService paymentService;

    @Test
    void testPaymentNotification_failure() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/payment/notification")
                .contentType(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsString(getPaymentNotificationRequest()))
                .header(HttpHeaders.AUTHORIZATION, "Bearer test-token"))
            .andExpect(status().is5xxServerError());

        // Assert that the retryable method was called 3 times
        Mockito.verify(paymentService, Mockito.times(3)).abc();
    }

    private PaymentNotificationRequest getPaymentNotificationRequest() {
        // build and return request
    }
}
```

> `@SpyBean` creates a proxy of the real Spring bean and allows us to verify method invocations.

* When the controller is triggered, `paymentService.abc()` is called.
* The method always throws `SomeRetryableException`, which triggers the retry logic.
* Spring Retry attempts the method 3 times (`maxAttempts = 3`).
* `@SpyBean` is used to spy on the real `PaymentService` bean.
* `Mockito.verify(..., times(3))` asserts that the method was retried exactly 3 times.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://www.pranaypourkar.co.in/the-programmers-guide/software-testing/java-test-framework/spring-test/mocking-in-spring-tests/verifying-retries-with-retryable.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
