spring容器中如何使用Mockito优雅的注入依赖的依赖

背景

我们知道使用Mockito的InjectMock和Mock/Spy注解可以把对应的依赖注入到被注解的实例中,比如有以下的分层架构:

@RequestMapping(/user)
class UserController implement Controller{
	@AutoWired
	UserService userService;
	@AutoWired
	UserDao userDao;
}

class UserService{
	@AutoWired
	UserDao userDao;
}

对于以上的分层方法的单元测试,我们可以这样写测试用例:

@RunWith(MockitoJUnitRunner.class)
public class UserControllerTest {
 
    @Mock
	UserDao userDao;
 
 	@Spy
	@AutoWired
	UserService userService;
 
    @InjectMocks
    private UserController userController ;
 
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }
 
    @Test
    public void test() throws Exception {
          Mickito.return("xxx").when(userService).method(Mickito.anyList())
    }
    

通过以上的方法我们可以把userService和userDao实例都注入到Controller实例中,但是请注意userService中的userDao这个对象并不是Mock的对象,而是真实的没有被mock过的对象,
这和我们想要的方式不一样。在我们理解中,userService中的userDao这个对象也应该是mock过的对象,而不是真实的对象,那么如何做到在所有用到userDao的地方使用的都是Mock对象,而不仅仅只是InjectMock里面的对象实例是使用了Mock的userDao实例呢?

答案是:没有简单的方法可以做到,但是可以通过曲线救国的方式达到这个效果

技术实现

前面讲完了一些背景知识,我们首先需要意识到一个对象被@Spy/@Mock修饰后,比如userDao对象,此时spring容器中会存在两个userDao对象实例,其中一个我们定义为EnhanceUserDao,一个我们称之为trueUserDao,我们在重温下在前面的例子中,userController和userService分别被注入的是什么dao对象,显然由于userController是使用InjectMock注解的,所以userController里面的dao对象是EnhanceUserDao,而userService对象是@spy注解的,里面的dao对象依然是真实的trueUserDao对象。那怎么做到userService里面也是使用被mock的dao对象EnhanceUserDao,而不是真实的trueUserDao对象呢

方法一

@RunWith(MockitoJUnitRunner.class)
public class UserControllerTest {
 
    @Mock
	UserDao userDao;
 
 	@Spy
	@AutoWired
	UserService userService;
 
    @InjectMocks
    private UserController userController ;
 
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
                ReflectionTestUtils.setField(userService, "userDao", userDao);

    }
 
    @Test
    public void test() throws Exception {
          Mickito.return("xxx").when(userService).method(Mickito.anyList())
    }

在初始化SetUp方法中使用 ReflectionTestUtils.setField(userService, “userDao”, userDao);方法把mock过的Dao对象注入到userService中,
这种实现对代码侵入性小,可以安全使用

方法二

首先service类要提供一个set方法

class UserService{
	@Setter
	@AutoWired
	UserDao userDao;
	
}

@RunWith(MockitoJUnitRunner.class)
public class UserControllerTest {
 
    @Mock
	UserDao userDao;
 
 	@Spy
	@AutoWired
	UserService userService;
 
    @InjectMocks
    private UserController userController ;
 
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        userService.setUserDao(userDao);
    }
 
    @Test
    public void test() throws Exception {
          Mickito.return("xxx").when(userService).method(Mickito.anyList())
    }

这种方法是在SetUp初始化的时候使用 userService.setUserDao(userDao);
把mock的EnhanceUserDao手动设置到userService类中,测试代码对源代码有侵入性(源代码需要增加setXX方法),所以不推荐

总结

当我们使用Mockito进行单元测试时,虽然我们使用了@spy等方法mock了某个类实例,但是并不是所有分层的类注入类实例都是这个被mock增强后的类,有可能还是真实的没有被mock增强的类,这个并没有一个简单的方法解决这个问题,本文只是提出了一个曲线救国的方法达到目的

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值