Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to override single bean defined in application context

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?

like image 981
tintin Avatar asked Mar 01 '12 16:03

tintin


People also ask

How do you override beans?

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.

What are the two methods of putting a bean in a context?

3.2. Beans are defined to be deployed in one of two modes: singleton or non-singleton.

Can we use @bean without @configuration?

@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.

What will happen if there are 2 beans with the same ID?

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.


2 Answers

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>
like image 65
seanhodges Avatar answered Nov 15 '22 07:11

seanhodges


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.

like image 32
nicholas.hauschild Avatar answered Nov 15 '22 07:11

nicholas.hauschild