java - 在 Spring 上重新注册单例 bean

标签 java spring unit-testing mocking

我有一个多模块项目,其中每个模块都有自己的单元测试,并为该模块的类提供模拟。

我正在尝试构建一个应用程序上下文,其中每个模块都可以定义自己的模拟,但稍后的单元测试将能够覆盖这些模拟,例如:

public class Test {

    private static final class StupidMock {
    }

    @org.junit.Test
    public void test() {
        StaticApplicationContext applicationContext = new StaticApplicationContext();
        final ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        StupidMock stupidMock = new StupidMock();  // original mock
        beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock);

        StupidMock f1 = applicationContext.getBean(StupidMock.class);
        if (f1 == null || f1 != stupidMock) {  // ensuring mock is retrievable
            fail("Could not get bean");
        }

        for (String names2Remove : beanFactory.getBeanNamesForType(StupidMock.class)) {
            applicationContext.removeBeanDefinition(names2Remove);  // <-- fails here 
        }

        StupidMock stupidMock2 = new StupidMock();     // replacement mock
        beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock2);
    }
}

问题是这个简单的片段在尝试删除第一个 mock 时失败了,声称没有这样的 bean(尽管 Spring 刚刚成功地为我提供了一个名称)。

如果我只是尝试在第一个 mock 之上注册另一个 mock,Spring 会提示说已经存在对象绑定(bind)。

DefaultSingletonBeanRegistry 有一个 protected removeSingleton 方法,但我无法控制 StaticApplicationContext 拥有的 bean 工厂。无论如何我都可以使用反射并调用这个 protected 方法,但是对于这样一个简单的任务这样做感觉不对。

我做错了什么?如何在 StaticApplicationContext 上实现单例替换?

最佳答案

这里的问题是 registerSingleton 方法实际上并没有创建相应的 BeanDefinition。 ,它只是注册实例化的单例,将其与您提供的名称相关联,并稍后通过应用程序上下文检索它——尽管它没有底层的 BeanDefinition。

因此,当您调用 applicationContext.removeBeanDefinition(names2Remove); 时,它失败了,因为没有 bean definition , 只有注册的完全实例化的 bean。

解决方法是不使用 registerSingleton,而是使用一种使用 BeanDefinition 的 registerSingleton 形式:

Map<String, String> map = new HashMap<String, String>();
map.put("i", "10"); // set all the properties for the mock..
MutablePropertyValues propertyValues = new MutablePropertyValues(map);

beanFactory.registerSingleton(StupidMock.class.getName(), StupidMock.class, propertyValues);

关于java - 在 Spring 上重新注册单例 bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11564926/

相关文章:

java - 如何在Java中获取完整的请求URL

java - 如何从电脑发送拨号字符串到 Asterisk 来调用电话?

java - Android - loopJ AsyncHttpClient 返回响应 onFinish 或 onSuccess

java - 使用 System.setOut() 重定向 Runtime.getRuntime().exec() 输出;

java - 如何在 spring-mvc 中为 REST 查询提供对象列表?

java - 从 Jar 中加载上下文

java - 奇怪的 Hibernate 缓存问题

java - 我如何使用 spring boot controller 进行 http post junit 测试

java - 写入将由 System.in、java 读取的输出

visual-studio - 实时测试不适用于 NUnit