Issue
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();
}
}
Answered By - Mark Bramnik
Answer Checked By - Senaida (JavaFixing Volunteer)