我有这个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
注释类的过滤器(