Search code examples
spring-bootjunitspring-retry

Write Junit test case for Spring Retry max atttemps


I would like to write a junit test case for spring retry, i tried like the below, but the junit is not working as expected. I am calling MaxAttemptRetryService.retry method, if it fails, it has to try for max 3 times. Here, Dao is calling a rest service, that is down, hence it should go trying for maximum 3 times. hence dao.sam method must be called 3 times.

Service Class:

@Service
@EnableRetry
public class MaxAttemptRetryService {   
    @Retryable(maxAttempts=3)
    public String retry(String username) throws Exception {
        System.out.println("retry???? am retrying...");
        int h = maxAttemptDao.sam();
        return "kkkk";
    }
}

Dao class:

@Component
public class MaxAttemptDao {
    public int sam() throws Exception{
        try{
            new RestTemplate()
            .getForObject("http://localhost:8080/greeting1/{userName}", 
                    String.class, "");
        }catch(Exception e){
            throw  e;
        }
        return 0;
    }
}

Test class:

@RunWith(SpringRunner.class)
public class HystrixServiceTest {

    @InjectMocks
    private MaxAttemptRetryService maxAttemptRetryService = new MaxAttemptRetryService();

    @Mock
    private MaxAttemptDao maxAttemptDao;

    @Test
    public void ff() throws Exception{
        when(maxAttemptDao.sam()).thenThrow(Exception.class);
        maxAttemptRetryService.retry("ll");
        verify(maxAttemptDao, times(3)).sam();
    }
}

Solution

  • @EnableRetry and @Retryable annotations should be processed by spring that is supposed to generate a proxy on-the-fly in runtime out of the DAO. The proxy will add the functionality of retry.

    Now when you're running a test, I don't see that it runs spring at all. You mentioned that you're running Spring Boot, but you don't use @SpringBootTest. On the other hand you also don't specify the configuration to load the class from (@ContextConfiguration annotation on HystrixServiceTest class)

    So I conclude that you don't initialize spring correctly and it can't process the @Retry annotation correctly as a result.

    Additional things that seem wrong to me:

    You should use @MockBean (if you start spring properly in the test) so that it won't just create a @Mock (for which you need a mockito runner BTW) but will create a mock spring bean and register it in an application context effectively overriding a standard bean declaration.

    I think you should do something like this:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class HystrixServiceTest {
    
      @Autowired // if everything worked right, you should get a proxy here actually (you can check that in debugger)
      private MaxAttemptRetryService maxAttemptRetryService;
    
      @MockBean
      private MaxAttemptDao maxAttemptDao;
    
    
      @Test
      public void ff() throws Exception{
          when(maxAttemptDao.sam()).thenThrow(Exception.class);
          maxAttemptRetryService.retry("ll");
          verify(maxAttemptDao, times(3)).sam();
      }
    
    
    }