Mocking Spring beans
I'd like to continue this question.
These answers foo and bar are exactly what I would need.
But for the bar example spring doesn't infer the type of bean that is returned from generic mock() method. But actually it's exactly the same as in the MockFactoryBean case, that is working.
class MockFactoryBean<T> implements开发者_C百科 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;
}
}
plus
<bean id="mockFactory" name="someType" class="com.example.MocksFactory" >
<property name="type" value="com.example.SomeType" />
</bean>
BUT using org.mockito.Mockito
and mock()
factory method doesn't work
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.example.SomeType" />
</bean>
and one gets No matching bean of type [ com.example.SomeType ] ... when Autowiring.
@Autowired public SomeType someType;
Why is that ?
the way with MockFactoryBean is quite inconvenient because if you have to mock many beans, you end up like this :
<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>
Because without id & name it doesn't infer the type.
When XML file should work with standard spring/mockito jars you can use ProxyFactoryBean and it works with autowiring (tested on 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>
I take that a step further with a bit more code in the FactoryBean and keep the real mock creation in my test class. Instead, my FactoryBean generates dynamic proxies as needed on Spring startup--which don't suffer the typing problem you're seeing--and the tests can wire in mocks as desired. I wrote a blog post that describes how to do it. The post specifically deals with testing a JAX-RS resource class, but the last section can pretty much stand on its own as an alternate way of doing what you're attempting if you blur out the JAX-RS stuff.
What I came up with:
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!");
}
}
}
And the definition:
<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>
Hope it will help those who are looking for the solution
精彩评论