构建Spring Retry自定义测试切片失败,请求排查问题
构建Spring Retry自定义测试切片失败,请求排查问题
正如标题所说,我正在尝试构建一个测试切片,用来测试标注了@Retryable的方法。我知道可以用@SpringBootTest这类启动完整上下文的注解来写测试,但我希望缩小Spring上下文的范围,只初始化需要的Bean来加快测试速度(同时也想借此学习Spring自定义测试切片的知识)。
我首先创建了一个新的@RetryTest注解:
@Target({ ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(DefaultTestContextBootstrapper.class) @ExtendWith({ SpringExtension.class }) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(RetryTypeExcludeFilter.class) public @interface RetryTest { @AliasFor("classes") Class<?>[] value() default {}; @AliasFor("value") Class<?>[] classes() default {}; }
同时还写了一个新的TypeExcludeFilter:
public final class RetryTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<RetryTest> { private static final Class<?>[] NO_CLASSES = new Class[0]; private static final Set<Class<?>> DEFAULT_INCLUDES; private final Class<?>[] classes; RetryTypeExcludeFilter(Class<?> testClass) { super(testClass); this.classes = (Class<?>[]) this.getAnnotation().getValue("classes", Class[].class).orElse(NO_CLASSES); } protected Set<Class<?>> getDefaultIncludes() { return DEFAULT_INCLUDES; } protected Set<Class<?>> getComponentIncludes() { return new LinkedHashSet<>(Arrays.asList(this.classes)); } static { Set<Class<?>> includes = new LinkedHashSet<>(); includes.add(EnableRetry.class); DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); } }
这个过滤器主要是参考WebMvcTypeExcludeFilter写的,我很喜欢它可以指定要实例化的具体控制器Bean的思路,但我把它改成了允许指定被测类。
测试类本身很简单,目前是这样的:
@RetryTest({ ClassUnderTest.class }) class ClassUnderTestTest { @Autowired ClassUnderTest classUnderTest; @Test void executeFunction_test() { Runnable runnable = mock(Runnable.class); doThrow(new RuntimeException("Error message")).when(runnable).run(); assertThatThrownBy(() -> classUnderTest.executeFunction(runnable, "Error message")) .isInstanceOf(CustomException.class); verify(runnable, times(3)).run(); } }
实际的被测类如下:
@Service @RequiredArgsConstructor public class ClassUnderTest { @Retryable(retryFor = { RuntimeException.class }) public <T> T executeFunction(Runnable functionCall, String errorDetails) { return functionCall.run(); } @Recover public <T> T executeAWSCall(RuntimeException e, Runnable functionCall, String errorDetails) { throw new CustomException(e, errorDetails); } }
不过现在我发现这个方案行不通。测试能跑起来,但没有在Spring上下文里运行,所以重试逻辑没有触发(我能看出来,因为抛出的是RuntimeException而不是CustomException)。
我主要怀疑三个地方可能出问题:
RetryTypeExcludeFilter里的getDefaultIncludes:说实话我完全不知道它在生命周期里什么时候被调用,也不知道怎么用,更不确定应该在里面包含哪些类。@BootstrapWith:我现在用的是默认测试上下文,因为我没看到WebMvcContext里有什么对重试有用或者必须的内容,但我也不确定这个注解到底有什么用,或者是不是根本不需要它。- 自动配置:很多现成的测试切片都会用自动配置和
@ImportAutoConfiguration来指定要实例化的Bean,但我不知道要让重试工作需要哪些Bean,所以目前我既没指定任何配置,也没引入现有的自动配置类。
备注:内容来源于stack exchange,提问作者EaterOfFromage
相关产品推荐
相关产品推荐

