java 单元测试:定义模拟行为后调用@PostConstruct

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38175822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 03:12:22  来源:igfitidea点击:

Unit testing: Call @PostConstruct after defining mocked behaviour

javaspringunit-testingmockitopostconstruct

提问by dwjohnston

I have two classes:

我有两个班级:

public MyService {
    @Autowired
    private MyDao myDao;     
    private List<Items> list; 

    @PostConstruct
    private void init(){
         list = myDao.getItems(); 
    }
}

Now I'm wanting to involve MyServicein a unit test, and so I'll mock the behaviour MyDao.

现在我想参与MyService单元测试,所以我将模拟行为MyDao

XML:

XML:

<bean class = "com.package.MyService"> 
<bean  class="org.mockito.Mockito" factory-method="mock"> 
     <constructor-arg value="com.package.MyDao"/>
</bean>

<util:list id="responseItems" value-type="com.package.Item">
    <ref bean="item1"/>
    <ref bean="item2"/>
</util:list>

Unit Test:

单元测试:

@ContextConfiguration("/test-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {

    @Autowired 
    MyService myService

    @Autowired 
    MyDao myDao;

    @Resource
    @Qualifier("responseItems")
    private List<Item> responseItems; 

    @Before
    public void setupTests() {
        reset(myDao); 
        when(myDao.getItems()).thenReturn(responseItems); 
    }
}

The problem with this is that the MyServicebean is created, and its @PostConstruct bean called before the mocked behaviour is defined.

这样做的问题MyService是创建了bean,并且在定义模拟行为之前调用了它的 @PostConstruct bean。

How can I either define the mocked behaviour in the XML or delay @PostConstructuntil after the unit test setup?

如何在 XML 中定义模拟行为或延迟@PostConstruct到单元测试设置之后?

回答by SS02

I have same kind of requirement in my project. where i need to set a string using @PostConstructor and I did not want to ran spring context or in other words I want simple mock. My requirement was follow:

我在我的项目中有同样的要求。我需要使用 @PostConstructor 设置一个字符串,但我不想运行 spring 上下文,或者换句话说,我想要简单的模拟。我的要求如下:

public class MyService {

@Autowired
private SomeBean bean;

private String status;

@PostConstruct
private void init() {
    status = someBean.getStatus();
} 

}

}

Solution:

解决方案:

public class MyServiceTest(){

@InjectMocks
private MyService target;

@Mock
private SomeBean mockBean;

@Before
public void setUp() throws NoSuchMethodException,  InvocationTargetException, IllegalAccessException {

    MockitoAnnotations.initMocks(this);

    when(mockBean.getStatus()).thenReturn("http://test");

    //call post-constructor
    Method postConstruct =  MyService.class.getDeclaredMethod("init",null); // methodName,parameters
    postConstruct.setAccessible(true);
    postConstruct.invoke(target);
  }

}

回答by UserF40

MyDao sounds like it is an abstraction of an external system. Generally external systems shouldn't be called in @PostConstructmethods. Instead have your getItems()called by another method in MyService.

MyDao 听起来像是对外部系统的抽象。通常不应在@PostConstruct方法中调用外部系统。而是让您getItems()MyService.

Mockito injections will take place after the Spring initiation at which point the mock isn't working as you see. You cannot delay the @PostConstruct. To beat this and have the load run automatically have MyServiceimplement SmartLifecycleand call getItems()in start().

Mockito 注入将在 Spring 启动之后进行,此时模拟无法如您所见。您不能延迟@PostConstruct. 要打败这个和有负荷运行自动拥有MyService执行SmartLifecycle和呼叫getItems()start()