我的Spring上下文中有几个bean有状态,所以我想在单元测试之前/之后重置该状态。
我的想法是向一个辅助类添加一个方法,该方法只遍历Spring上下文中的所有bean,检查用@Before
或@After
注释的方法并调用它们。
如何从ApplicationContext
获取实例化 bean列表?
注意:简单地遍历所有定义的bean的解决方案是无用的,因为我有许多懒惰的bean,其中一些不能被实例化,因为对于某些测试会失败(即我有一个需要java.sql.DataSource
的bean但是测试工作是因为他们不需要那个bean。)
答案 0 :(得分:21)
例如:
public static List<Object> getInstantiatedSigletons(ApplicationContext ctx) {
List<Object> singletons = new ArrayList<Object>();
String[] all = ctx.getBeanDefinitionNames();
ConfigurableListableBeanFactory clbf = ((AbstractApplicationContext) ctx).getBeanFactory();
for (String name : all) {
Object s = clbf.getSingleton(name);
if (s != null)
singletons.add(s);
}
return singletons;
}
答案 1 :(得分:3)
我不确定这是否会对您有所帮助。
您需要创建自己的注释,例如。 MyAnnot。 并将该注释放在您想要获得的类上。 然后使用以下代码,您可能会获得实例化的bean。
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnot.class));
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("com.xxx.yyy")){
System.out.println(beanDefinition.getBeanClassName());
}
通过这种方式,您可以获得具有自定义注释的所有bean。
答案 2 :(得分:3)
我必须稍微改进一下
@Resource
AbstractApplicationContext context;
@After
public void cleanup() {
resetAllMocks();
}
private void resetAllMocks() {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
for (String name : context.getBeanDefinitionNames()) {
Object bean = beanFactory.getSingleton(name);
if (Mockito.mockingDetails(bean).isMock()) {
Mockito.reset(bean);
}
}
}
答案 3 :(得分:1)
applicationContext.getBeanDefinitionNames()不会不显示在没有 BeanDefinition实例的情况下注册的Bean。
package io.velu.core;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class Core {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Core.class);
String[] singletonNames = context.getDefaultListableBeanFactory().getSingletonNames();
for (String singleton : singletonNames) {
System.out.println(singleton);
}
}
}
environment
systemProperties
systemEnvironment
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
messageSource
applicationEventMulticaster
lifecycleProcessor
如您在输出中看到的,将使用 context.getBeanDefinitionNames()方法不显示环境,systemProperties,systemEnvironment Bean。
对于Spring Boot Web应用程序,可以使用以下端点列出所有bean。
@RestController
@RequestMapping("/list")
class ExportController {
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/beans")
@ResponseStatus(value = HttpStatus.OK)
String[] registeredBeans() {
return printBeans();
}
private String[] printBeans() {
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
if (autowireCapableBeanFactory instanceof SingletonBeanRegistry) {
String[] singletonNames = ((SingletonBeanRegistry) autowireCapableBeanFactory).getSingletonNames();
for (String singleton : singletonNames) {
System.out.println(singleton);
}
return singletonNames;
}
return null;
}
}
[ “ autoConfigurationReport”, “ springApplicationArguments”, “ springBootBanner”, “ springBootLoggingSystem”, “环境”, “系统属性”, “ systemEnvironment”, “ org.springframework.context.annotation.internalConfigurationAnnotationProcessor”, “ org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory”, “ org.springframework.boot.autoconfigure.condition.BeanTypeRegistry”, “ org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry”, “ propertySourcesPlaceholderConfigurer”, “ org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store”, “ preserveErrorControllerTargetClassPostProcessor”, “ org.springframework.context.annotation.internalAutowiredAnnotationProcessor”, “ org.springframework.context.annotation.internalRequiredAnnotationProcessor”, “ org.springframework.context.annotation.internalCommonAnnotationProcessor”, “ org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor”, “ org.springframework.scheduling.annotation.ProxyAsyncConfiguration”, “ org.springframework.context.annotation.internalAsyncAnnotationProcessor”, “ methodValidationPostProcessor”, “ embeddedServletContainerCustomizerBeanPostProcessor”, “ errorPageRegistrarBeanPostProcessor”, “ messageSource”, “ applicationEventMulticaster”, “ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration $ EmbeddedTomcat”, “ tomcatEmbeddedServletContainerFactory”, “ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration $ TomcatWebSocketConfiguration”, “ websocketContainerCustomizer”, “ spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties”, “ org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration”, “ localeCharsetMappingsCustomizer”, “ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration”, “ serverProperties”, “ duplicateServerPropertiesDetector”, “ spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties”, “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration $ DefaultErrorViewResolverConfiguration”, “ conventionErrorViewResolver”, “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration”, “ errorPageCustomizer”, “ servletContext”, “ contextParameters”, “ contextAttributes”, “ spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties”, “ spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties”, “ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration”, “ multipartConfigElement”, “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration $ DispatcherServletRegistrationConfiguration”, “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration $ DispatcherServletConfiguration”, “ dispatcherServlet”, “ dispatcherServletRegistration”, “ requestContextFilter”, “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration”, “ hiddenHttpMethodFilter”, “ httpPutFormContentFilter”, “ characterEncodingFilter”, “ org.springframework.context.event.internalEventListenerProcessor”, “ org.springframework.context.event.internalEventListenerFactory”, “ reportGeneratorApplication”, “ exportController”, “ exportService”, “ org.springframework.boot.autoconfigure.AutoConfigurationPackages”, “ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration”, “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ Jackson2ObjectMapperBuilderCustomizerConfiguration”, “ spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties”, “ standardJacksonObjectMapperBuilderCustomizer”, “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ JacksonObjectMapperBuilderConfiguration”, “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration”, “ jsonComponentModule”, “ jacksonObjectMapperBuilder”, “ org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration $ JacksonObjectMapperConfiguration”, “ jacksonObjectMapper”, “ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration”, “ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration”, “ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration”, “ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration”, “ defaultValidator”, “ org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration $ WhitelabelErrorViewConfiguration”, “错误”, “ beanNameViewResolver”, “ errorAttributes”, “ basicErrorController”, “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ EnableWebMvcConfiguration”, “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ WebMvcAutoConfigurationAdapter”, “ mvcContentNegotiationManager”, “ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration $ StringHttpMessageConverterConfiguration”, “ stringHttpMessageConverter”, “ org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration $ MappingJackson2HttpMessageConverterConfiguration”, “ mappingJackson2HttpMessageConverter”, “ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration”, “ messageConverters”, “ mvcConversionService”, “ mvcValidator”, “ requestMappingHandlerAdapter”, “ mvcResourceUrlProvider”, “ requestMappingHandlerMapping”, “ mvcPathMatcher”, “ mvcUrlPathHelper”, “ viewControllerHandlerMapping”, “ beanNameHandlerMapping”, “ resourceHandlerMapping”, “ defaultServletHandlerMapping”, “ mvcUriComponentsContributor”, “ httpRequestHandlerAdapter”, “ simpleControllerHandlerAdapter”, “ handlerExceptionResolver”, “ mvcViewResolver”, “ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration $ WebMvcAutoConfigurationAdapter $ FaviconConfiguration”, “ faviconRequestHandler”, “ faviconHandlerMapping”, “ defaultViewResolver”, “ viewResolver”, “ welcomePageHandlerMapping”, “ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration”, “ objectNamingStrategy”, “ mbeanServer”, “ mbeanExporter”, “ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration”, “ springApplicationAdminRegistrar”, “ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration”, “ org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration”, “ spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties”, “ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration”, “ multipartResolver”, “ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration $ RestTemplateConfiguration”, “ restTemplateBuilder”, “ org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration”, “ spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties”, “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ RestartConfiguration”, “ fileSystemWatcherFactory”, “ classPathRestartStrategy”, “ classPathFileSystemWatcher”, “ hateoasObjenesisCacheDisabler”, “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ LiveReloadConfiguration $ LiveReloadServerConfiguration”, “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration $ LiveReloadConfiguration”, “ OptionalLiveReloadServer”, “ org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration”, “ lifecycleProcessor” ]
答案 4 :(得分:0)
我创建了gist ApplicationContextAwareTestBase。
这个助手类做了两件事:
它将所有内部字段设置为null。这允许Java释放不再使用的内存。尽管如此,它对Spring的用处不大(Spring上下文仍保留对所有bean的引用)。
它尝试查找上下文中所有bean中使用@After
注释的所有方法,并在测试后调用它们。
这样,您可以轻松地重置单身/模拟的状态,而不必破坏/刷新上下文。
示例:您有一个模拟DAO:
public void MockDao implements IDao {
private Map<Long, Foo> database = Maps.newHashMap();
@Override
public Foo byId( Long id ) { return database.get( id ) );
@Override
public void save( Foo foo ) { database.put( foo.getId(), foo ); }
@After
public void reset() { database.clear(); }
}
注释将确保在每次单元测试后调用reset()
以清理内部状态。
答案 5 :(得分:0)
使用之前的答案,我已将此更新为使用Java 8 Streams API:
@Inject
private ApplicationContext applicationContext;
@Before
public void resetMocks() {
ConfigurableListableBeanFactory beanFactory = ((AbstractApplicationContext) applicationContext).getBeanFactory();
Stream.of(applicationContext.getBeanDefinitionNames())
.map(n -> beanFactory.getSingleton(n))
// My ConfigurableListableBeanFactory isn't compiled for 1.8 so can't use method reference. If yours is, you can say
// .map(ConfigurableListableBeanFactory::getSingleton)
.filter(b -> Mockito.mockingDetails(b).isMock())
.forEach(Mockito::reset);
}