• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
lixia0417mul2
帮助1

背景

我们知道使用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增强的类,这个并没有一个简单的方法解决这个问题,本文只是提出了一个曲线救国的方法达到目的

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbjbik
系列文章
更多 icon
同类精品
更多 icon
继续加载