Sumedh
Sumedh

Reputation: 435

Use a mock object if specific service not found

In our unit tests, we usually configure all dependencies as EasyMocks...and configure them...in the spring context xml file, we need to add these dependencies something like this -

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

where EasyMockNiceCreator is an implementation of Spring FactoryBean which creates a EasyMock.createNiceMock() in the getObject() method.

How can I make this a default configuration, so that spring will use this configuration if it doesn't find an explicitly defined autowired dependency, a fallback.

Upvotes: 1

Views: 394

Answers (1)

suthar
suthar

Reputation: 11

i think this code will help -

Auto bean creator

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

Mock factory class

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>

all service autowired in Target class will be mocked.

Upvotes: 1

Related Questions