在运行JUnit5测试时,我如何覆盖Spring组件扫描



我有这个JUnit 5测试:

@SpringBootTest
public class MyTest {
...
}

应用程序默认配置加载许多@Component@Service@Configuration

对于一些测试,我想告诉在这个JUnit测试上下文中运行的Spring应用程序不要扫描所有组件,并过滤掉一些重载或冗长/垃圾邮件的组件,这些组件在(模拟的(环境中运行时可能会抱怨,因为在这种环境中并不能满足所有要求。

我试图以下面的形式为MyTest类提供@ComponentScan注释。我特意添加了多个过滤器和多个类型,希望在应用程序上下文中加载/注册更少的bean:

@ComponentScan(
useDefaultFilters = false,
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {
org.springframework.context.annotation.Configuration.class,
org.springframework.stereotype.Service.class,
org.springframework.stereotype.Component.class
}),
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
MyRabbitMqListener.class
})
}
)
@SpringBootTest
public class MyTest {
@Autowired
private ApplicationContext context;
@Test
public void expectingLessRegisteredBeans() {
List<String> beans = Arrays.stream(context.getBeanDefinitionNames())
// ...
.collect(Collectors.toList());
assertEquals(beans.size(), ...);
}
}

不管我向@CompoenntScan提供了什么,我都无法控制在JUnit5Spring测试上下文中扫描/注册的bean的数量。

但我仍然想使用@SpringBootTest来获得我的应用程序的大部分配置,但排除了其中的一些部分(因为它们很慢,或者在日志中垃圾邮件,或者只是抛出错误(。例如,从Kafka、RabbitMQ或REST等输入接收事件的应用程序会对其进行处理并将其保存到持久层。我想测试处理和持久性集成。我向处理器@Service抛出一堆测试事件,然后期望通过@Repository在DB中看到结果。

我的替代方案是什么:

  • 为@SpringBootTest提供我想要加载的类的白名单(不优雅,乏味(
  • 定义几个Spring配置文件,在组件上放置条件注释,只激活/停用测试代码中需要的配置文件,还使用不同的配置文件application-*.properties来静音一些日志记录(非测试代码需要被这个测试特性污染,并且创建多个配置文件很乏味(
  • 从头开始构建应用程序上下文的其他方法(虽然我实际上想要的是使用我的应用程序配置,但与某些测试无关的部分除外(

您可以使用org.springframework.boot.test.context.filter.TypeExcludeFilter

在您的@SpringBootTest注释集成测试中添加一个@TypeExcludeFilters(YourCustomTypeExcludeFilter.class)注释,它将使用您实现的TypeExcludeFilter从测试的ApplicationContext中筛选出您不想要的bean。


@SpringBootTest
@TypeExcludeFilters(YourCustomTypeExcludeFilter.class)
public class MyTest {
@Autowired
private ApplicationContext context;
@Test
public void expectingLessRegisteredBeans() {
List<String> beans = Arrays.stream(context.getBeanDefinitionNames())
// ...
.collect(Collectors.toList());
assertEquals(beans.size(), ...);
}
}

一个按类名排除bean的简单TypeExcludeFilter如下所示:

public class YourCustomTypeExcludeFilter extends TypeExcludeFilter {
private static final List<String> beanNamesToExclude = List.of(
"org.personal.MyRabbitMqListener");
@Override
public boolean equals(Object obj) {
return (obj != null) && (getClass() == obj.getClass());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
return beanNamesToExclude.stream()
.anyMatch(beanName -> metadataReader.getClassMetadata().getClassName().equals(beanName));
}
}

Sky是可以与match()方法一起使用的逻辑的极限。为了获得更多可能的灵感,只需在Spring Boot源代码中搜索扩展TypeExcludeFilter的类(例如,查看org.springframework.boot.test.context.filter.TestTypeExcludeFilter,一个用于排除@TestConfiguration注释类的过滤器(

相关内容

  • 没有找到相关文章

最新更新