Spring中如何使用Mockito做单元测试

在Spring服务层和持久层做单元测试时,面对注解注入的类,Mockito提供了解决方案。通过@Mock和@Spy注解,可以方便地注入Mock对象。@Mock会完全替换真实实例,而@Spy则允许部分调用真实方法。对于Spring的AOP代理类,若想混合使用Mock和真实实例,目前可能需要创建两个测试类分别处理。在定义方法调用时,可以使用anyXXX()匹配任意参数,但若一个参数使用了anyXXX(),所有参数都需如此。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Spring环境下做单元测试常常遇到很多问题,Controller层还好说,Spring本身提供了很多方法来支持,这个可以看我的另一篇文章

http://blog.youkuaiyun.com/ynwso/article/details/8672310


但是在服务层和持久层,如果是使用注解注入的方式来设计的话,用Mock来替换真实的注入类就很麻烦了,还好我们有Mockito框架。但一段代码,你会发现它比easyMock好用多了

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:application-context-test.xml" })
public class RouteServiceTestCase{
   @InjectMocks
   @Autowired
   private IRouteService service;

   @Mock
   private IRouteMatrixDataProvider provider;

   @Before
   public void myBefore() {
       MockitoAnnotations.initMocks(this);
   }

   @Test
   public void testGetAirlineCode() {
       RouteMatrix rm = new RouteMatrix();
       rm.setAirlineCode("kkk");
       Mockito.when(this.provider.getRevenueRoute("HKG", "AMM", true)).thenReturn(rm);
       String code = this.service.getAirlineCode("HKG", "AMM", this.brand, this.cInfo, true);
       Assert.assertNotNull(code);
       Assert.assertEquals("kkk", code);
       code = this.service.getAirlineCode("HKG", "KKK", this.brand, this.cInfo, true);
       Assert.assertNull(code);
   }

   @Test
   public void testGetAirlineCode2() {
       String code = this.service.getAirlineCode("HKG", "AMM", this.brand, this.cInfo, true);
       Assert.assertNotNull(code);
       Assert.assertEquals("kkk", code);
   }
}

@Spy
@Autowired
private IRouteMatrixDataProvider provider;


service 被标记了 @InjectMocks , 在 myBefore方法中 执行 MockitoAnnotations.initMocks(this); 的时候,会将标记了 @Mock 或 @Spy 的属性注入到 service 中。
如果是 @Mock, 那就是通常的方式,service里面的provider完全被Mock实例替换,所有的调用都是针对Mock生成类的。
如果是 @Autowired 加 @Spy , 那么对于定制了返回值的会调用 Mock实例,否则会调用真实注入的属性,但是这里有一个限制,如果是代理类会报错,比如Spring 的AOP代理。 
对于AOP的代理类,如果想一部分用Mock,一部分用真实的实例,感觉目前是有些困难,暂时想到的办法就是写两个测试类,一个注入真实属性,一个注入mock属性。


方法调用时,如果不想指定一个明确的参数,就可以用下面这样的写法来表示任意的参数。

Mockito.when(this.provider.getRevenueRoute(Matchers.anyString(), Matchers.anyString(), Matchers.anyBoolean()))
           .thenReturn(rm);

但是这里也有一个限制就是,如果有一个参数使用了any***(),则所有的参数都必需使用这种方式,不能像下面这样写

Mockito.when(this.provider.getRevenueRoute(Matchers.anyString(), Matchers.anyString(), true))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值