javaspringmavenjunitspring-retry

Spring's @Retryable not working when running JUnit Test


I have this test:

@RunWith(MockitoJUnitRunner.class)
public class myServiceTest {

@InjectMocks
myService subject;

private myService spy;

@Before
public void before() {
    spy = spy(subject);
}

@Test
public void testing() {

    when(spy.print2()).thenThrow(new RuntimeException()).thenThrow(new RuntimeException()).thenReturn("completed");
    spy.print1();
    verify(spy, times(3)).print2();
}

and then I have:

@Service("myService")
public class myService extends myAbstractServiceClass {


public String print1() {
    String temp = "";
    temp = print2();
    return temp;
}

 @Retryable
 public String print2() {
     return "completed";
 }
}

then I have this interface(which my abstractService implements):

public interface myServiceInterface {

    @Retryable(maxAttempts = 3)
    String print1() throws RuntimeException;

    @Retryable(maxAttempts = 3)
    String print2() throws RuntimeException;

}

but, I get a runtimeexception thrown when I run the test, leading me to believe it is not retrying. Am I doing this wrong?


Solution

  • This is because you are not using the SpringJUnitClassRunner.

    Mockito and your own classes are not taking the @Retryable annotation in account. So you rely on the implementation of Spring to do so. But your test does not activate Spring.

    This is from the SpringJUnit4ClassRunner JavaDoc:

    SpringJUnit4ClassRunner is a custom extension of JUnit's BlockJUnit4ClassRunner which provides functionality of the Spring TestContext Framework to standard JUnit tests by means of the TestContextManager and associated support classes and annotations. To use this class, simply annotate a JUnit 4 based test class with @RunWith(SpringJUnit4ClassRunner.class) or @RunWith(SpringRunner.class).

    You should restructure your test class at least to something like:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=MyConfig.class)
    public class MyServiceTest {
        @Configuration
        @EnableRetry
        @Import(myService.class)
        public static class MyConfig {}
    ...
    

    What am I doing there?

    1. activate the Spring JUnit hook
    2. specify the Spring context configuration class
    3. define the spring configuration and import your service as a bean
    4. enable the retryable annotation

    Are there some other pitfalls?

    Hope that helps.