12

I'm writing an integration test where an application context xml is initialized during startup. There are several test methods in the test class which make use of a specific bean 'X'(already defined in the xml). My actual requirement is to mock bean X only for one of the test methods.

Inside a test method: I tried creating a separate application context using ClassPathXMLApplicationContext with only the mock bean 'M'.

Now I have two Application Contexts (AC): 1. One created during test case startup (which contains the actual bean X) and 2. One created using ClassPathXMLApplicationContext within the test method (which has the mock bean M).

I want to replaced the actual bean definition 'X' within AC:1, using the mock bean definition 'M' from AC:2.

Can somebody throw some light on this please?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Ram
  • 191
  • 1
  • 2
  • 12

3 Answers3

23

You can :

  • use the Profile annotation if you have spring 3.1.
  • use the Primary annotation
  • use qualifiers
  • wire the bean yourself in the spring context

and i'm sure there are even more options.

G-Man
  • 1,321
  • 8
  • 15
  • 2
    **@Primary** is the best answer: "Indicates that a bean should be given preference when multiple candidates are qualified to autowire (...)" – jsosnowski Nov 16 '15 at 16:14
  • For me \@Primary is also the best Answer, but what happen when when \@Qualifier is used? – deFreitas May 30 '16 at 18:44
  • Really liked the @Primary suggestion. This is very helpful in special test scenarios... – Martin Jul 12 '17 at 10:26
17

There is not a clear way to replace a a bean in a refreshed ApplicationContext unless you close it and refresh it again.

To emulate it, the common approach is to use a Proxy of the bean that you want to replace and change the target at runtime.

You can do it easily using the framework aop support classes:

<bean id="realBean" class="RealClass" />
<bean id="mockBean" class="MockClass" />
<bean id="targetSource" class="org.springframework.aop.target.HotSwappableTargetSource">
    <constructor-arg ref="realBean" />
</bean>

<bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="targetSource" />
</bean>

 

@Test
public void testWithMockBean() {
Object real = targetSource.swap(mock);
....
// do your test work
...
targetSource.swap(real);

}
harschware
  • 13,006
  • 17
  • 55
  • 87
Jose Luis Martin
  • 10,459
  • 1
  • 37
  • 38
  • I tried this out in a small example. The gist is here: https://gist.github.com/harschware/111416de4c8fe53689b8c5ca15140a67 – harschware May 23 '18 at 22:29
3

Create a testApplicationContext with

<beans>
    <import resource="classpath*:appContext.xml" />
    <bean id="mockbeanOfX" class=....../>
</beans>

and then load this test application context in your testcase. Now you can get the mock bean from the application context and pass it whereever needed.

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Chandru
  • 964
  • 11
  • 16