Spring的@Retryable在运行JUnit Test时无法正常工作

Pro*_*att 6 java junit spring maven spring-retry

我有这个测试:

@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();
}
Run Code Online (Sandbox Code Playgroud)

然后我有:

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


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

 @Retryable
 public String print2() {
     return "completed";
 }
}
Run Code Online (Sandbox Code Playgroud)

然后我有这个接口(我的abstractService实现):

public interface myServiceInterface {

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

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

}
Run Code Online (Sandbox Code Playgroud)

但是,当我运行测试时,我得到了一个运行时异常抛出,导致我认为它没有重试.我做错了吗?

Joh*_*mer 8

这是因为你没有使用SpringJUnitClassRunner.

Mockito和你自己的类没有考虑@Retryable注释.所以你依靠Spring的实现来做到这一点.但是你的测试没有激活Spring.

这是来自SpringJUnit4ClassRunner JavaDoc:

SpringJUnit4ClassRunner是JUnit的BlockJUnit4ClassRunner的自定义扩展,它通过TestContextManager和相关的支持类和注释为标准JUnit测试提供Spring TestContext Framework的功能.要使用此类,只需使用@RunWith(SpringJUnit4ClassRunner.class)或@RunWith(SpringRunner.class)注释基于JUnit 4的测试类.

您应该至少将测试类重组为以下内容:

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

我在那做什么?

  1. 激活Spring JUnit钩子
  2. 指定Spring上下文配置类
  3. 定义spring配置并将服务导入为bean
  4. 启用可重试注释

还有其他一些陷阱吗?

  • 是的,您正在使用Mockito来模拟异常.如果你想像这样用Spring测试这种行为,你应该看一下Springockito Annotations.
  • 但请注意:Springockito你将完全替换spring bean,这会迫使你代理你的可重试的调用.你需要一个像这样的结构:test -> retryableService -> exceptionThrowingBean.然后你可以使用Springockito或任何你喜欢的东西,例如ReflectionTestUtils配置exceptionThrowingBean你喜欢的行为.
  • 您应该在测试中引用服务的接口类型: MyServiceInterface
  • 最后但并非最不重要.几乎所有Java开发人员都遵循命名约定:类名具有first letter of each internal word capitalized

希望有所帮助.


Jus*_*tas 6

Another way:

@EnableRetry
@RunWith(SpringRunner.class)
@SpringBootTest(classes={ServiceToTest.class})
public class RetryableTest {

    @Autowired
    private ServiceToTest serviceToTest;

    @MockBean
    private ComponentInsideTestClass componentInsideTestClass;

    @Test
    public void retryableTest(){
        serviceToTest.method();
    }

}
Run Code Online (Sandbox Code Playgroud)