Question

Note: I have purposefully removed words from the names of classes and objects, so please excuse the horribly names in my code examples

I've got a test class that sets up my application using some test Spring context files. The application is a wrapper to a web service.

As this is a test, I have mocked the main interface to the web service in question (the ITransporter class). This gives me the ability to set expectations so that I can check that the requests sent to the web service are: in the expected format; have the expected fields complete; etc...

My mock is defined in a file called test-beans-context.xml and is passed into some service beans, as follows:

<bean id="mockTransporter" class="org.easymock.EasyMock" factory-method="createMock" scope="singleton">
    <constructor-arg index="0" value="transport.ITransporter" />
</bean>
<bean id="accountService" class="service.AccountService">
    <property name="transporter" ref="mockTransporter" />
</bean>

This context file is used in 2 places. (And I fear this is where my problem arises.)

The first being the test class, which is defined as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( locations={"classpath:test-beans-context.xml"} )
public class AbstractIntegrationTest {

    @Autowired
    private ITransporter mockTransporter;

    //Some tests that perform expectations like the following:
    //  EasyMock.reset( this.mockTransporter );
    //  EasyMock.expect( this.mockTransporter.sendRequest( EasyMock.capture(this.requestXmlCapture) ) ).andReturn( responseXml );
}

The second place is in a class that is within the logical trail for getting to sending the request. It loads a separate XML context file /lite-api-context.xml that then imports the test one in my test set up.

public class Factory implements IFactory {
    public Factory() {
        context = new ClassPathXmlApplicationContext("/lite-api-context.xml");
    }
    @Override
    public IAccountService getAccountService() {
        return (IAccountService) context.getBean("accountService");
    }
}

And lite-api-context.xml includes this:

<import resource="classpath:/test-beans-context.xml" />

My problem is that in the test class, I'm getting a different instance of the mocked ITransporter to the one that is ultimately being used by my other services. So the expectations I set up are never actually executed as the mocks end up being different instances.

Is there a way to ensure I get the same instance in both places?

Or am I going to have to create my own singleton test implementation of the ITransporter interface? (Basically creating a stub that behaves exactly like my mock does now.)

EDIT: (Answer)

As The Thom said, it appears I need to create my own class to manage the mock.

I wanted to add my solution here too in case anyone stumbled across a similar problem.

Just wrote a quick static class like this:

public class MockTransporter {

    private static ITransporter mockTransporter = EasyMock.createMock(ITransporter.class);

    public static final ITransporter getInstance() {
        return mockTransporter;
    }
}

And had to change the XML config to this:

<bean id="mockTransporter" class="MockTransporter" factory-method="getInstance" />
Was it helpful?

Solution

Oh yeah, that's a problem. When you create a new context that's like creating a new object space for Spring. The one created in your XML file is different from the one created in your handmade context. They will always produce different variables.

I've been burned on that one before.

You're only hope if you want the same ones is to manage your own singletons.

OTHER TIPS

The ideal way to solve this problem would be to create the Factory as a Spring bean as well, and inject the AccountService into the Factory bean. In general context.getBean() should be avoided in production code because it harms the concept of Inversion of Control (for more information see: Why is Spring's ApplicationContext.getBean considered bad?). It's okay to use it in test code though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top