简体   繁体   English

Spring配置模拟给出两个不同的实例

[英]Spring configured mock giving two different instances

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. 我有一个测试类,它使用一些测试Spring上下文文件来设置我的应用程序。 The application is a wrapper to a web service. 该应用程序是Web服务的包装器。

As this is a test, I have mocked the main interface to the web service in question (the ITransporter class). 由于这是一个测试,我已经模拟了有问题的Web服务的主界面( ITransporter类)。 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; 这使我能够设置期望,以便我可以检查发送到Web服务的请求是否:以预期的格式; 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: 我的mock在一个名为test-beans-context.xml的文件中定义,并传递给一些服务bean,如下所示:

<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. 此上下文文件用于2个位置。 (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. 它加载一个单独的XML上下文文件/lite-api-context.xml ,然后在我的测试设置中导入测试文件。

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: lite-api-context.xml包括:

<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. 我的问题是,在测试类中,我得到了一个不同的模拟ITransporter实例,最终被我的其他服务使用。 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? 或者我将不得不创建自己的ITransporter接口的单例测试实现? (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. 正如The Thom所说,似乎我需要创建自己的类来管理模拟。

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: 并且必须将XML配置更改为:

<bean id="mockTransporter" class="MockTransporter" factory-method="getInstance" />

Oh yeah, that's a problem. 哦,是的,这是一个问题。 When you create a new context that's like creating a new object space for Spring. 当您创建一个新的上下文时,就像为Spring创建一个新的对象空间一样。 The one created in your XML file is different from the one created in your handmade context. 在XML文件中创建的文件与在手工上下文中创建的文件不同。 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. 你只希望如果你想要相同的是管理你自己的单身人士。

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. 解决此问题的理想方法是将Factory创建为Spring bean,并将AccountService注入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? ). 通常,在生产代码中应避免使用context.getBean(),因为它会损害控制反转的概念(有关更多信息,请参阅: 为什么Spring的ApplicationContext.getBean被认为是错误的? )。 It's okay to use it in test code though. 可以在测试代码中使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM