我有这个测试:
@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();
}
然后我有:
@Service("myService")
public class myService extends myAbstractServiceClass {
public String print1() {
String temp = "";
temp = print2();
return temp;
}
@Retryable
public String print2() {
return "completed";
}
}
然后我有这个接口(interface)(我的 abstractService 实现):
public interface myServiceInterface {
@Retryable(maxAttempts = 3)
String print1() throws RuntimeException;
@Retryable(maxAttempts = 3)
String print2() throws RuntimeException;
}
但是,我在运行测试时抛出了运行时异常,这让我相信它没有重试。我做错了吗?
最佳答案
这是因为您没有使用 SpringJUnitClassRunner
.
Mockito 和您自己的类没有考虑 @Retryable
注释。所以你依赖于 Spring 的实现来做到这一点。但是您的测试不会激活 Spring。
这是来自 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).
您应该至少将您的测试类重构为:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=MyConfig.class)
public class MyServiceTest {
@Configuration
@EnableRetry
@Import(myService.class)
public static class MyConfig {}
...
我在那里做什么?
- 激活 Spring JUnit 钩子(Hook)
- 指定Spring上下文配置类
- 定义 spring 配置并将您的服务作为 bean 导入
- 启用可重试注解
还有其他陷阱吗?
- 是的,您正在使用 Mockito 来模拟异常。如果你想像这样用 Spring 测试这种行为,你应该看看 Springockito Annotations .
- 但请注意:Springockito 将完全替换 spring bean,这会迫使您代理可重试的调用。您需要这样的结构:
test -> retryableService -> exceptionThrowingBean
。然后你可以使用 Springockito 或任何你喜欢的东西,例如ReflectionTestUtils
以您喜欢的行为配置exceptionThrowingBean
。 - 您应该在测试中引用服务的接口(interface)类型:
MyServiceInterface
- 最后但并非最不重要的一点。有一个几乎所有 Java 开发人员都遵循的命名约定:类名
每个内部单词的第一个字母大写
希望对您有所帮助。
关于java - Spring 的 @Retryable 在运行 JUnit 测试时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39478665/