问题描述
我有这个测试:
@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";
}
}
然后我有这个接口(我的abstractService实现了):
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?
推荐答案
这是因为您没有使用 SpringJUnitClassRunner
.
This is because you are not using the SpringJUnitClassRunner
.
Mockito和您自己的类未考虑@Retryable
注释.因此,您需要依靠Spring的实现.但是您的测试不会激活Spring.
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.
这来自SpringJUnit4ClassRunner JavaDoc:
This is from the SpringJUnit4ClassRunner JavaDoc:
您应该至少将测试类重组为以下内容:
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 {}
...
我在那里做什么?
- 激活Spring JUnit钩子
- 指定Spring上下文配置类
- 定义spring配置并将您的服务作为Bean导入
- 启用可重试注释
还有其他陷阱吗?
- 是的,您正在使用Mockito模拟异常.如果您想像这样用Spring测试这种行为,您应该看看 Springockito注释.
- 但是请注意:Springockito将完全替换spring bean,这将迫使您代理可重试的调用.您需要这样的结构:
test -> retryableService -> exceptionThrowingBean
.然后,您可以使用Springockito或任何您喜欢的东西,例如ReflectionTestUtils
使用您喜欢的行为配置exceptionThrowingBean
. - 您应该在测试中引用服务的接口类型:
MyServiceInterface
- 最后但并非最不重要的一点.几乎所有Java开发人员都遵循一个命名约定:类名带有
first letter of each internal word capitalized
- Yes, you are using Mockito to simulate an exception. If you want to test this behaviour with Spring like this, you should have a look at Springockito Annotations.
- But be aware of that: Springockito you will replace the spring bean completely which forces you to proxy the call of your retryable. You need a structure like:
test -> retryableService -> exceptionThrowingBean
. Then you can use Springockito or what ever you like e.g.ReflectionTestUtils
to configure theexceptionThrowingBean
with the behaviour you like. - You should reference the interface type of your service in your test:
MyServiceInterface
- And last but not least. There is a naming convention nearly all Java developers follow: class names have
first letter of each internal word capitalized
希望有帮助.
这篇关于运行JUnit Test时Spring的@Retryable无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!