Spring beans redefinition in unit test environment Spring beans redefinition in unit test environment spring spring

Spring beans redefinition in unit test environment


I would propose a custom TestClass and some easy rules for the locations of the spring bean.xml:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {    "classpath*:spring/*.xml",    "classpath*:spring/persistence/*.xml",    "classpath*:spring/mock/*.xml"})@Transactional@TestExecutionListeners({    DependencyInjectionTestExecutionListener.class,    TransactionalTestExecutionListener.class,    DirtiesContextTestExecutionListener.class})public abstract class AbstractHibernateTests implements ApplicationContextAware {    /**     * Logger for Subclasses.     */    protected final Logger log = LoggerFactory.getLogger(getClass());    /**     * The {@link ApplicationContext} that was injected into this test instance     * via {@link #setApplicationContext(ApplicationContext)}.     */    protected ApplicationContext applicationContext;    /**     * Set the {@link ApplicationContext} to be used by this test instance,     * provided via {@link ApplicationContextAware} semantics.     */    @Override    public final void setApplicationContext(            final ApplicationContext applicationContext) {        this.applicationContext = applicationContext;    }}

If there are mock-bean.xml in the specified location, they will override all "real" bean.xml files in the "normal" locations - your normal locations might differ.

But … I would never mix mock and non-mock beans, as it's hard to trace problems when the application grows older.


One of the reasons spring is described as test-friendly is because it may be easy to just new or mock stuff in the unit test.

Alternately we have used the following setup with great success, and I think it is quite close to what you want, I would strongly recommend it:

For all beans that need different implementations in different contexts, switch to annotation based wiring. You can leave the others as-is.

Implement the following set of annotations

 <context:component-scan base-package="com.foobar">     <context:include-filter type="annotation" expression="com.foobar.annotations.StubRepository"/>     <context:include-filter type="annotation" expression="com.foobar.annotations.TestScopedComponent"/>     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> </context:component-scan>

Then you annotate your live implementations with @Repository, your stub implementations with @StubRepository, any code that should be present in the unit-test fixture ONLY with @TestScopedComponent. You may run into needing a couple more annotations, but these are a great start.

If you have a lot of spring.xml, you will probably need to make a few new spring xml files that basically only contain the component-scan definitions. You'd normally just append these files to your regular @ContextConfiguration list. The reason for this is because you frequently end up with different configurations of the context-scans (trust me, you will make at least 1 more annotations if you're doing web-tests, which makes for 4 relevant combinations)

Then you basically use the

@ContextConfiguration(locations = { "classpath:/path/to/root-config.xml" })@RunWith(SpringJUnit4ClassRunner.class)

Note that this setup does not allow you to have alternating combinations of stub/live data. We tried this, and I think that resulted in a mess I wouldn't recommend anyone ;) We either wire inn the full set of stubs or the full set of live services.

We mainly use auto-wired stub dependencies when testing gui near stuff where the dependencies are usually quite substantial. In cleaner areas of the code we use more regular unit-testing.

In our system we have the following xml-files for component-scan:

  • for regular web production
  • for starting web with stubs only
  • for integration tests (in junit)
  • for unit tests (in junit)
  • for selenium web tests (in junit)

This means we totally have 5 different system-wide configurations that we can start the application with. Since we only use annotations, spring is fast enough to autowire even those unit tests we want wired. I know this is untraditional, but it's really great.

Out integration tests run with full live setup, and once or twice I have decided to get really pragmatic and want to have a 5 live wirings and a single mock:

public class HybridTest {   @Autowired   MyTestSubject myTestSubject;   @Test   public void testWith5LiveServicesAndOneMock(){     MyServiceLive service = myTestSubject.getMyService();     try {          MyService mock = EasyMock.create(...)          myTestSubject.setMyService( mock);           .. do funky test  with lots of live but one mock object     } finally {          myTestSubject.setMyService( service);     }   }}

I know the test purists are going to be all over me for this. But sometimes it's just a very pragmatic solution that turns out to be very elegant when the alternative would be really really ugly. Again it's usually in those gui-near areas.


See this tutorial with @InjectedMock annotation

It saved me a lot of time. You just use

@MockSomeClass mockedSomeClass@InjectMockClassUsingSomeClass service@Beforepublic void setUp() {    MockitoAnnotations.initMocks(this);}

and all your problems are solved. Mockito will replace the spring dependency injection with a mock. I just used it myself and it works great.