单元自测Mockito和PowerMockito总结

Mockito官方文档

Mockito和PowerMockito的区别

PowerMockito可以mock private、final、static等方法。

@InjectMocks和@Mock的区别

@InjectMocks
Service service;

@Mock
Person person;

@Mock创建一个mock service,当你需要测试的类/方法中有依赖的类,可以将依赖的类mock掉,底层原理是通过代理的方式。比如Service类中的功能依赖了Person类,那么可以将Person类mock掉。该方式可以获得Person类包含的所有方法,而通过mock(person)调用其任何方法一般都返回null、空或0值,他不会调用真实方法。

@InjectMocks创建一个实例对象,他是可以调用真实的方法的,通过service调用其方法是真实的。而@Mock(@Spy)创建的mock会被注入到该实例中。

@Mock和@Spy的区别

一般推荐使用@Mock,但是总是会出现一个类,你想要mock掉一部分方法,但是有另一部分你希望是可以真实调用的,这时你可以使用@Spy

Person p = PowerMockito.spy(new Person());

此时,你想要在spy对象(p)上打桩,不能够使用when(),而是doReturn()|doThrow()|doAnswer()|doNothing()|doCallRealMethod()家族。如mockito文档中举的例子:

   List list = new LinkedList();
   List spy = spy(list);

   //Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
   when(spy.get(0)).thenReturn("foo");

   //You have to use doReturn() for stubbing:
   doReturn("foo").when(spy).get(0);
 

具体例子

public class Check{
    private final A a;
    private final B b;
    public Check(A a,B b){
        this.a = a;
        this.b = b;
    }
    //保证SimpleDateFormat的线程安全性
    private static final ThreadLocal<DateFormat> DATE_FORMAT_YYYYMMDD = ThreadLocal.withInitial(()->new SimpleDateFormat("yyyyMMdd"));
    private static final ThreadLocal<DateFormat> DATE_FORMAT_YYYYMM = ThreadLocal.withInitial(()->new SimpleDateFormat("yyyyMM"));

    public void sink(Record record){
        if(record == null){
            log.info("record:检核结果为null");
        }
        try{
            String yyyyMM;
            String yyyyMMdd;
            if(null != record.getProcessTime()){
                yyyyMM = DATE_FORMAT_YYYYMM.get().format(record.getProcessTime());

                yyyyMMdd = DATE_FORMAT_YYYYMM.get().format(record.getProcessTime());
            }else{
                log.info("recon:统计时间为空");
                return;
            }
            if(StringUtils.isEmpty(yyyyMM)||StringUtils.isEmpty(yyyyMMdd)){
                log.info("record统计时间出错:{}",record.getProcessTime());
                return;
            }
            if(!updateKey(record,yyyyMMdd){
                return;
            }
            Response response = saveObject(record,yyyyMM);
            log.info("存储{}到数据库成功",response);
        }catch(Exception e){
            log.erro("sink异常",e);
        }
    }
    private boolean updateKey(Record record,String s){
.....
    }
    private Response saveObject(Record record,String s){
......
    }
}
  1. 测试当record为null
@RunWtih(PowerMockRunner.class)
public class CheckTest{
    @InjectMocks
    Check check;

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

    @Test
    public void sink_recoedIsNull(){
        Record record = PowerMockito.spy(new Recod());
        check.sink(null);
        //因为需要在record判断其方法procesTime是否被调用,如果使用mock,则会导致没有调用processTime,那么这个verify(never次)永远成立,所以,这里要使用spy
        Mockito.verify(record,Mockito.never()).getProcessTime();
    }
}

          

2. 测试record的字段processTime字段为null

如果processTime为空,那么StringUtils不会调用isEmpty方法。是对StringUtils的静态方法的mock

@Test
    @PreparedForTest(StringUtils.class)
    public void sink_ProcessTimeIsNull(){
        Record record = new Record();
        PowerMockito.mockStatic(StringUtils.class);
        check.sink(record);
        PowerMockito.verifyStatic(StringUtils.class,Mockito.never());
        StringUtils.isEmpty(anyString());
    }

3. 测试yyyyMM, yyyyMMdd时间转换出错

PowerMockito.verifyPrivate(mock,.....),需要一个mock对象,但是又要验证对check的私有方法进行验证,所以这里用了spy对象

@Test
    @PreparedForTest(value={StringUtils.class,Check.class})
    public void sink_ProcessTimeWrong(){
        Record record = new Record();
        record.setProcessTime(new Date());

        PowerMockito.mockStatic(StringUtils.class);
        PowerMockito.when(StringUtils.isEmpty(anyString())).thenReturn(true);
        A a = PowerMockito.mock(A.class);
        B b = PowerMOckito.mock(B.class);
        Check check1 = PowerMockito.spy(new Check(a,b));
        check.sink(record);
        try{
            PowerMockito.verifyPrivate(check1,Mockito.never()).invoke("updateKey",any(Record.class),anyString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

4. 测试更新成功情况

@Test
    @PreparedForTest(value={StringUtils.class,Check.class})
    public void sink_KeyUpdateSuccess(){
        Record record = new Record();
        record.setProcessTime(new Date());

        PowerMockito.mockStatic(StringUtils.class);
        PowerMockito.when(StringUtils.isEmpty(anyString())).thenReturn(false);

        A a = PowerMockito.mock(A.class);
        B b = PowerMOckito.mock(B.class);
        Check check1 = PowerMockito.spy(new Check(a,b));
        try{
            //必须使用doReturn
            PowerMockito.doReturn(true).when(check1,"updateKey",any(Record.class),anyString());
            check.sink(record);
            PowerMockito.verifyPrivate(check1,Mockito.times(1)).invoke("saveObject",any(Record.class),anyString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值