I have a web application which accesses an external web service. I'm writing an automated acceptance test suite for the web application. I do not want to invoke the external web service as it has serious overhead, I want to mock this web service. How can acheive this without changing the application context of the web application? We recently migrated to Spring 3.1 so I'm tempted to use the new environment features. Would these new feature help me in overriding this single web service and leave application context as it is?
Bean Overriding Spring beans are identified by their names within an ApplicationContext. Therefore, bean overriding is a default behavior that happens when we define a bean within an ApplicationContext that has the same name as another bean. It works by simply replacing the former bean in case of a name conflict.
3.2. Beans are defined to be deployed in one of two modes: singleton or non-singleton.
@Bean methods may also be declared within classes that are not annotated with @Configuration. For example, bean methods may be declared in a @Component class or even in a plain old class. In such cases, a @Bean method will get processed in a so-called 'lite' mode.
Here, @Bean instantiates two beans with ids the same as the method names and registers them within the BeanFactory (Spring container) interface. Next, we can initialize the Spring container and request any of the beans from the Spring container. This strategy also makes it simple to achieve dependency injection.
I would use the Spring @Profile feature, which I assume is the "environment features" you were referring to.
For example:
@Service @Profile("dev")
public class FakeWebService implements WebService {
}
@Service @Profile("production")
public class ExternalWebService implements WebService {
}
EDIT
And to specify which profile to use in your test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/app-config.xml")
@ActiveProfiles("dev")
public class MyAcceptanceTest {
}
See this section of the Spring docs for more details.
There are several ways to set the active profile in production, but the method I've used before is in the web.xml:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>
I would use a BeanFactoryPostProcessor
to do this, which is only registered in the test scenarios that you want this mocked.
The BeanFactoryPostProcessor
allows you to modify the Application Context immediately after it is created and populated. You can look for the name of your specific bean, and register a different bean for it.
public class SystemTestBeanFactoryPostProcessor implements BeanFactoryPostProcessor
{
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory factory) throws BeansException
{
final MyInterface myInterface = new MyInterfaceStub();
factory.registerSingleton("myInterfaceBeanName", myInterface);
}
}
This will allow you to overwrite only the beans that you want to stub/mock.
I am not sure that this is the 'newest 3.x' way to do this sort of thing. But it is very straightforward and easy to implement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With