简体   繁体   English

模拟对象和Spring注释

[英]Mock object and Spring annotations

I am using Spring annotations in my code to do the DI. 我在我的代码中使用Spring注释来完成DI。 So lets say I have a class class1 that depends on another class class2, I define class1 as below: 所以假设我有一个依赖于另一个类class2的类class1,我将class1定义如下:

@Component
public class class1 {

@Resource
private interface2 object2;

}

class2 is an implementation of interface2. class2是interface2的一个实现。

Now lets say I want to mock class2 and pass it to class1, I dont see any constructor or setter in class1. 现在让我说我想模拟class2并将它传递给class1,我在class1中看不到任何构造函数或setter。 I think Spring uses reflection to inject object2. 我认为Spring使用反射来注入object2。 How can I mock it? 我怎么嘲笑它? Should I add a setter in class1? 我应该在class1中添加一个setter吗? Or can I reuse the same way spring is doing it - I mean does spring itself have a mock object framework or something, I was planning to use EasyMock for the mocking. 或者我可以像Spring一样重复使用它 - 我的意思是spring本身有一个模拟对象框架或者什么,我打算使用EasyMock进行模拟。

Thanks 谢谢

The ReflectionTestUtils class in Spring might be helpful. Spring中的ReflectionTestUtils类可能会有所帮助。
It seems to do what you are looking for...at least the injection part :-) 它似乎做你正在寻找...至少注射部分:-)

Mockito has a really powerful way of handling mocks and DI: Mockito有一个非常强大的处理模拟和DI的方法:

@RunWith(MockitoJUnitRunner.class)
public class Class1Test {
    @Mock
    private Interface2 inteface2mock;

    @InjectMocks
    private Class1 class1;

    @Test
    public void someTest() {
        when(interface2mock.doSomething("arg")).thenReturn("result");

        String actual = class1.doSomeThatDelegatesToInterface2();

        assertEquals("result", actual);
    }
}

Read more about @InjectMocks in the Mockito javadoc or in a blog post that I wrote about the topic some time ago. 了解更多关于@InjectMocks中的javadoc的Mockito或在博客中 ,我前段时间写的话题。

Available as of Mockito 1.8.3, enhanced in 1.9.0. 自Mockito 1.8.3起可用,增强型1.9.0。

ReflectionTestUtils is the easiest to add the mock you want (we use JMock, but it does not really matter), drawback is that it is slightly brittle. ReflectionTestUtils是最容易添加你想要的模拟(我们使用JMock,但它并不重要),缺点是它稍微脆弱。 If you rename the field, you must remember to change the test as well. 如果重命名该字段,则必须记住也要更改测试。

You can also use this: http://i-proving.com/2006/11/09/using-jmock-and-inject-object/ 你也可以使用它: http//i-proving.com/2006/11/09/using-jmock-and-inject-object/

It describes how to use a mocked object in a spring context. 它描述了如何在spring上下文中使用模拟对象。

AFAIK, there is no mocking framework built into Spring, so you need to use something like EasyMock. AFAIK,Spring中没有内置的模拟框架,所以你需要使用像EasyMock这样的东西。 The way I have done this in the past is to 我过去这样做的方式是

  • Define the Spring config using XML instead of annotations* 使用XML而不是注释定义Spring配置*
  • The config for the main app is defined in appContext-main.xml and the test config (the mock objects) is defined in appContext-test.xml 主应用程序的配置在appContext-main.xml定义,测试配置(模拟对象)在appContext-test.xml定义
  • A mock bean in appContext-test.xml must have the same ID as the corresponding bean in appContext-main.xml appContext-test.xml mock bean必须与appContext-main.xml相应的bean具有相同的ID
  • When the app runs only appContext-main.xml is loaded 当应用程序运行时,仅加载appContext-main.xml
  • When the tests run both appContext-main.xml and appContext-test.xml are loaded. 当测试运行时, appContext-main.xmlappContext-test.xml Make sure that they are loaded in this order so that the mocks 'override' any beans of the same name 确保它们按此顺序加载,以便模拟“覆盖”任何同名的bean

* You don't need to need to convert all your Spring configuration to XML to use this approach. *您无需将所有 Spring配置转换为XML即可使用此方法。 Only those beans that have mock implementations or have mock implementations injected into them need to be changed. 只有那些具有模拟实现或注入模拟实现的bean才需要更改。 The others bean can continue to be defined with annotations. 其他bean可以继续使用注释定义。

Injecting yourself via reflection is very easy, so you can avoid the setter method. 通过反射注入自己非常容易,因此您可以避免使用setter方法。

To do it yourself is like this: 自己做就是这样的:

    for (Field field : injectable.getClass().getDeclaredFields()) {
        MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
        if (annotation != null) {
            field.setAccessible(true);
            Object param = generateMockObject();
            field.set(injectable, param);
        }
    }

There is a JUnit Rule that gives EasyMock similar annotation-driven injection capabilities, in the manner of Mockito. 有一个JUnit规则,以Mockito的方式为EasyMock提供类似的注释驱动注入功能。 See EasyMockRule 请参阅EasyMockRule

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

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