如果找不到特定服务,请使用模拟对象

时间:2012-09-18 06:42:06

标签: spring easymock

在我们的单元测试中,我们通常将所有依赖项配置为EasyMocks ...并配置它们...在spring context xml文件中,我们需要添加这样的依赖项 -

<bean id="myService" class="mypackage.EasyMockNiceCreator">
        <property name="iface"
                  value="myservicePackage.MyService"/>
</bean>

其中EasyMockNiceCreator是Spring FactoryBean的一个实现,它在getObject()方法中创建一个EasyMock.createNiceMock()。

如何将其设置为默认配置,以便如果找不到明确定义的自动连接依赖关系,则spring将使用此配置。

1 个答案:

答案 0 :(得分:1)

我认为这段代码会有所帮助 -

自动创建者

import com.google.common.collect.Iterables;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AutoBeanDeclarer implements BeanDefinitionRegistryPostProcessor {

    private Collection<String> mockedDefinitions;

    public AutoBeanDeclarer() {
        mockedDefinitions = new ArrayList<String>();
    }

    private Iterable<Field> findAllAutoWired(Class targetBean) {
        List<Field> declaredFields = Arrays.asList(targetBean.getDeclaredFields());
        return Iterables.filter(declaredFields, new Predicate<Field>() {
            @Override
            public boolean apply(Field input) {
                return input.isAnnotationPresent(Autowired.class);
            }
        });
    }

    private void registerOn(final BeanDefinitionRegistry registry,final String beanName, final Class type){
        RootBeanDefinition definition = new RootBeanDefinition(MocksFactory.class);

        MutablePropertyValues values = new MutablePropertyValues();
        values.addPropertyValue(new PropertyValue("type", type));
        definition.setPropertyValues(values);

        registry.registerBeanDefinition(beanName, definition);
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        for(String beanName: registry.getBeanDefinitionNames()) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            String beanClassName = beanDefinition.getBeanClassName();
            try {
                Class beanClass = Class.forName(beanClassName);
                for (final Field field : findAllAutoWired(beanClass)) {
                    String fieldName = field.getName();
                    boolean invalidType = field.getType().isArray() || field.getType().isPrimitive();
                    if( invalidType ) {
                        continue;
                    }
                    if( !registry.isBeanNameInUse(fieldName) ) {
                        registerOn(registry, fieldName, field.getType());
                        mockedDefinitions.add(fieldName);
                        // Now field will be available for autowiring.
                    }
                }
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(AutoBeanDeclarer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for(String beanName: mockedDefinitions) {
            if( !beanFactory.containsBean(beanName) ) {
                Logger.getLogger(AutoBeanDeclarer.class.getName()).log(Level.SEVERE, "Missing definition %s", beanName);
            }
        }
    }
}

模拟工厂类

import org.mockito.Mockito;
import org.springframework.beans.factory.FactoryBean;

public class MocksFactory implements FactoryBean {

    private Class type;// the created object type

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

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

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

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

<强> context.xml中

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <bean id="autoConfigurer" class="....AutoBeanFinder"></bean>

    <bean id="targetClass" class="....Target"></bean>

</beans>
  

在Target类中自动装配的所有服务都将被模拟。