模拟Spring beans

4
我想继续讨论这个问题
这些答案foobar正是我所需要的。
但对于bar示例,Spring无法推断从通用mock()方法返回的bean类型。但实际上它与MockFactoryBean的情况完全相同,而后者是有效的。
class MockFactoryBean<T> implements FactoryBean<T> {

    private Class<T> type;

    public void setType(final Class<T> type) {
        this.type = type;
    }

    @Override
    public T getObject() throws Exception {
        return (T) Mockito.mock(type);
    }

    @Override
    public Class<T> getObjectType() {
        return type;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

加号

<bean id="mockFactory" name="someType" class="com.example.MocksFactory" >
    <property name="type" value="com.example.SomeType" />
</bean>

但是使用org.mockito.Mockitomock()工厂方法并不起作用。

<bean id="dao" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.example.SomeType" /> 
</bean> 

当自动装配时,会出现“找不到类型为[com.example.SomeType]的匹配bean”的错误。

@Autowired public SomeType someType;

为什么会这样呢?

MockFactoryBean的方式相当不方便,因为如果您必须模拟多个bean,最终会得到以下结果:

<bean id="mockFactory1" name="metadataExtractor" class="tests.base.MocksFactory" >
    <property name="type" value="processing.MetadataExtractor" />
</bean>
<bean id="mockFactory2" name="fileValidator" class="tests.base.MocksFactory" >
    <property name="type" value="validation.file.FileValidator" />
</bean>
<bean id="mockFactory3" name="documentMatcher" class="tests.base.MocksFactory" >
    <property name="type" value="validation.matching.DocumentMatcher" />
</bean>
<bean id="mockFactory4" name="uploadMatcher" class="tests.base.MocksFactory">
    <property name="type" value="validation.matching.UploadMatcher" />
</bean>
<bean id="mockFactory5" name="tempFileLocalService" class="tests.base.MocksFactory">
    <property name="type" value="service.TempFileLocalService" />
</bean>
<bean id="mockFactory6" name="orderLocalService" class="tests.base.MocksFactory">
    <property name="type" value="service.OrderLocalService" />
</bean>
<bean id="mockFactory7" name="counterLocalService" class="tests.base.MocksFactory">
    <property name="type" value="service.CounterLocalService" />
</bean>

因为没有id和name,它不能推断出类型。


这个例子对我来说非常酷。 - Mike
3个回答

7
当XML文件需要与标准的Spring/Mockito JAR一起使用时,您可以使用ProxyFactoryBean,并且它可以与自动装配一起使用(在Spring 2.5上进行了测试)。
<bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
   <property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
</bean> 

0
我想到的是:
public class SpringMocks implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(SpringMocks.class);
    private final List<Class<?>> classes;

    public SpringMocks(List<Class<?>> classes) {
        this.classes = classes;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (applicationContext instanceof GenericApplicationContext) {
            GenericApplicationContext context = (GenericApplicationContext) applicationContext;
            DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

            for (Class<?> className : classes) {
                String beanName = RandomStringUtils.randomAlphanumeric(10);
                Object singletonObject = Mockito.mock(className);
                beanFactory.registerSingleton(beanName, singletonObject);
            }
        } else {
            logger.warn("unable to add beans to the context!");
        }
    }
}

还有定义:

<bean class="com.whatever.SpringMocks">
    <constructor-arg index="0">
        <list>
            <value>com.whatever.enricher.Enricher</value>
            <value>com.whatever.nimbus.NimbusOrderDao</value>
            <value>com.whatever.nimbus.NimbusAllocationDao</value>
            <value>com.whatever.nimbus.NimbusExecutionDao</value>
            <value>com.whatever.nimbus.NimbusBookingInstructionDao</value>
            <value>com.whatever.services.SettingsService</value>
            <value>com.whatever.matchers.utils.CVDataRetriever</value>
        </list>
    </constructor-arg>
</bean>

希望这能帮助那些正在寻找解决方案的人。

0

我在 FactoryBean 中增加了更多的代码,并将真正的模拟创建保留在测试类中。相反,我的 FactoryBean 在 Spring 启动时根据需要生成动态代理--它们不会出现您看到的类型问题--并且测试可以根据需要连接模拟。我写了一篇博客文章来描述如何实现它。这篇文章专门讲解如何测试 JAX-RS 资源类,但最后一节基本上可以独立作为执行您正在尝试的操作的另一种方式,如果您忽略 JAX-RS 的内容。


做得很好,但我已经习惯了只留下那些一眼就能看出来的解决方案。这需要很多集中注意力才能理解,而且其他程序员和我自己在一段时间后也会如此重复 :-) - lisak
@lisak:我喜欢使用它,正是因为相反的原因:它让你保持以往编写测试的方式不变,所以没有什么新东西需要适应。 - Ryan Stewart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接