PowerMock 私有/公共方法和静态方法对doReturn..when 和 when.thenReturn的不同表现

背景:

今天使用powermock的时候同事说被mock的私有/公共方法一直报空指针异常,但是mock静态类并没有异常,觉得很奇怪,本文就来讲下powermock私有/公共方法和静态方法对于doReturn…when 和 when.thenReturn的不同表现,以及使用时的注意事项

追查真相

首先看下用来mock测试的私有方法和静态方法类,如下图所示:

public class MyPrivateMethod {


    private String myPrivateFunc(Integer num){
        String result = "private:" + num.toString();
        return result;
    }

    public String myShow(Integer num){
        return myPrivateFunc(num) + "_xxxxx";
    }

}
public class MyStaticMethod {

    public static String myStaticFunc(Long num) {
        String result = "static:" + num.toString();
        return result;
    }

    public String myDisplay(Long num) {
        return myStaticFunc(num) + "_yyyyy";
    }

}

其次是我们使用来测试的代码:

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest({MyPrivateMethod.class, MyStaticMethod.class})
public class PowerMockTest {

    /**
     * 对于私有和共有方法的mock 1. when().thenReturn的方式会使用mock的参数调用被mock的方法,产生副作用,比如这里的空指针异常
     */
    @Test
    public void testPrivate0() throws Exception {
        MyPrivateMethod inst = PowerMockito.spy(new MyPrivateMethod());
        // 这种方式会使用Mockito.any()也就是null对象调用myPrivateFunc函数,此时就会产生空指针异常
        PowerMockito.when(inst, "myPrivateFunc", Mockito.any()).thenReturn("mockPrivateResult");
        Integer num = 100;
        String ret = inst.myShow(num);
        Assert.assertTrue(ret.equals("mockPrivateResult_xxxxx"));
    }

    /**
     * 对于私有和共有方法的mock 1. doReturn().when不会产生额外的副作用,这其实才是真正我们想要的.
     */
    @Test
    public void testPrivate1() throws Exception {
        MyPrivateMethod inst = PowerMockito.spy(new MyPrivateMethod());
        // 这种方式不会实际调用myPrivateFunc方法,所以不会产生异常
        PowerMockito.doReturn("mockPrivateResult").when(inst, "myPrivateFunc", Mockito.any());
        Integer num = 100;
        String ret = inst.myShow(num);
        Assert.assertTrue(ret.equals("mockPrivateResult_xxxxx"));
    }


    /**
     * 静态方法的mock
     * 1.不论是使用when().thenReturn的方式还是doReturn.when的方式都不会产生副作用
     * */
    @Test
    public void testStatic() throws Exception {
        MyStaticMethod inst = PowerMockito.spy(new MyStaticMethod());
        PowerMockito.mockStatic(MyStaticMethod.class);
         PowerMockito.when(MyStaticMethod.myStaticFunc(Mockito.any())).thenReturn("myStaticFunc");
//        PowerMockito.doReturn("myStaticFunc").when(MyStaticMethod.class, "myStaticFunc", Mockito.any());
        Long num = 1000L;
        String ret = inst.myDisplay(num);
        Assert.assertTrue(ret.equals("myStaticFunc_yyyyy"));
    }


}

对于mock私有和公共方法来说异常如下:

java.lang.NullPointerException
	at org.example.pmock.MyPrivateMethod.myPrivateFunc(MyPrivateMethod.java:7)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.example.pmock.PowerMockTest.testPrivate0(PowerMockTest.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)

由于对于mock私有和公共方法来说,when.doReturn会使用mock的参数实际调用被mock方法,虽然对于静态方法来说不会这样,但是为了统一,还是推荐mock方法是统一使用doReturn…when的方式来mock数据

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值