【问题标题】:Unit testing: Call @PostConstruct after defining mocked behaviour单元测试:定义模拟行为后调用@PostConstruct
【发布时间】:2016-11-05 15:51:40
【问题描述】:

我有两个班级:

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

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

现在我想让MyService 参与单元测试,因此我将模拟MyDao 的行为。

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>

单元测试:

@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); 
    }
}

这个问题是MyService bean 被创建,它的@PostConstruct bean 在定义模拟行为之前被调用。

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

【问题讨论】:

    标签: java spring unit-testing mockito postconstruct


    【解决方案1】:

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

    Mockito 注入将在 Spring 启动后进行,此时模拟无法正常工作。您不能延迟@PostConstruct。为了解决这个问题并让负载自动运行,让MyService 实现SmartLifecycle 并在start() 中调用getItems()

    【讨论】:

    • 是的 - 我认为您可能是对的,通常我的问题表明我应该解决的代码异味。
    【解决方案2】:

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

    public class MyService {
    
    @Autowired
    private SomeBean bean;
    
    private String status;
    
    @PostConstruct
    private void init() {
        status = someBean.getStatus();
    } 
    

    }

    解决方案:

    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);
      }
    
    }
    

    【讨论】:

    • 完美解决方案
    • 完美解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-24
    • 2016-08-24
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 2018-08-31
    相关资源
    最近更新 更多