我有一个多模块项目,每个模块都有自己的单元测试,并为该模块的类提供模拟。
我正在尝试构建一个应用程序上下文,其中每个模块都可以定义自己的模拟,但后来的单元测试可以覆盖这些模拟,例如:
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);
}
}
问题是这个简单的片段在尝试删除第一个模拟时失败,声称没有这样的bean(虽然Spring刚刚成功地为我提供了一个名字)。
如果我只是尝试在第一个上面注册另一个模拟,Spring抱怨说已经存在对象限制。
DefaultSingletonBeanRegistry
有removeSingleton
方法受保护,但我无法控制StaticApplicationContext
拥有的bean工厂。我可以使用反射并且无论如何都要调用这个受保护的方法,但是对于这样一个简单的任务来说这样做是错误的。
我做错了什么?我怎样才能在StaticApplicationContext
上实现单例替换?
答案 0 :(得分:2)
这里的问题是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);
答案 1 :(得分:2)
您可以使用spring-reinject重新定义bean。
答案 2 :(得分:1)
如果您使用的是spring框架,为什么不使用Spring testing framework
您可以使用以下注释在每个单元测试的基础上进行特定的模拟
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)