2013-02-12 32 views
17

我的Spring环境中有几个bean有状态,所以我想在单元测试之前/之后重置该状态。如何从Spring获取实例化bean的列表?

我的想法是添加一个方法到一个助手类,它只是通过Spring上下文中的所有bean,检查用@Before@After注释并调用它们的方法。

如何获得实例化的豆类列表ApplicationContext

注:简单地遍历所有定义的bean是无用的,因为我有很多懒豆,其中一些不能被实例化,因为这将失败的一些测试(即我有需要java.sql.DataSource一个咖啡豆,但测试解决方案因为他们不需要这个bean)。

+1

也许定义 “后” 切入点HTTP:/ /static.springsource.org/spring/docs/3.0.x/reference/aop.html – 2013-02-12 11:52:15

+0

你的单元测试中的@DirtiesContext注释没有做到你想要的吗? – 2013-02-12 12:30:32

+0

@NicolasMommaerts:不。重新设置几个bean会比从头创建整个上下文便宜得多。 – 2013-02-12 14:50:01

回答

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; 

    } 
+0

'getSingleton()'完全适合我。更新了我的要点(请参阅我自己的回答) – 2013-02-12 15:24:31

+0

@AaronDigulla我正在使用'Spring-WebMVC'。我怎样才能访问我的'DispatcherServlet'的'WebApplicationContext'?没有它,我无法迭代instanciated bean。 – smwikipedia 2015-11-03 07:41:47

+1

@AaronDigulla我解决了它。我可以使用'ApplicationContextAware'接口。参考:http://stackoverflow.com/questions/9602664/print-all-the-spring-beans-that-areloaded – smwikipedia 2015-11-03 08:54:39

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。

0

我创建了一个gist ApplicationContextAwareTestBase

这个辅助类做了两两件事:

  1. 它集所有内部字段设置为null。这允许Java释放不再使用的内存。尽管如此,它对Spring的用处不大(Spring上下文仍然保留对所有bean的引用)。

  2. 它试图在上下文中的所有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()将每个单元测试后,被要求清理内部状态。

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); 
     } 
    } 
} 
0

使用以前的答案,我已经更新了这个用Java 8流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); 
} 
相关问题