PowerMock中@mock和@spy在mock私有方法的区别,使用@spy模拟私有方法进行测试时sonar统计是有覆盖率的

1. 问题描述 

PowerMock使用@spy进行模拟私有方法返回值进行测试时,私有方法中的代码总是会被执行

(如果私有方法中依赖环境等因素,测试则难以进行)

例如如下代码段,需要测试callSumXX方法,同时想要模拟私有方法sumXX的返回值

public class Calculator {
    private int sumXX(int a, int b) {
        return a + b;
    }

    public int callSumXX(int a, int b) {
        return sumXX(a, b);
    }
}

编写如下测试代码进行单元测试调试:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
    @Test
    public void testSumXX() throws Exception {
        Calculator cal= PowerMockito.spy(new Calculator());
        PowerMockito.when(cal,"sumXX",anyInt(),anyInt()).thenReturn(2);
        assertEquals(2, cal.callSumXX(1, 2));
    }
}

发现私有方法的代码总是会被执行,而预期的是私有方法就不应该执行:

查看了下,发现@spy和@mock的对象在使用when...thenReturn有区别:

@mock写法: cal中所有的方法都不是真实的且默认返回null,用mock去模拟返回值时sumXX方法会先执行一次,而因为执行的不是真实的方法所以并没有什么影响。

 Calculator cal=PowerMockito.mock(Calculator.class);

PowerMockito.when(cal,"sumXX",anyInt(),anyInt()).thenReturn(2);

assertEquals(2, cal.callSumXX(1, 2));

@spy写法: cal中所有的方法都是真实的,用when..thenReturn时就会去执行真实的私有方法,那么私有方法里面所有的代码都会执行一遍,这样是不可行的,因为很有可能私有方法就会依赖真实的环境。需要改用doReturn..when才会不执行真实的方法。

Calculator cal=PowerMockito.spy(new Calculator());

PowerMockito.doReturn(2).when(cal,"sumXX",anyInt(),anyInt());

assertEquals(2, cal.callSumXX(1, 2));

 

2. 使用@mock和@spy两种方式模拟私有方法进行测试的区别

使用@mock模拟私有方法测试代码如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
    @Test
    public void testSumXX() throws Exception {
        Calculator cal = PowerMockito.mock(Calculator.class);
        PowerMockito.when(cal,"sumXX",anyInt(),anyInt()).thenReturn(2);
        //指明callSumXX调用真实的方法
        PowerMockito.when(cal.callSumXX(anyInt(),anyInt())).thenCallRealMethod();
        assertEquals(2, cal.callSumXX(1, 2));
    }
}

注:因为@mock出来的对象可能已经发生了变化,调用的方法都不是真实的,@mock出来的Calculator对应已经不是原来的Calculator,在进行sonar覆盖率统计时统计出来的Calculator类覆盖率为0.00%.

使用@spy模拟私有方法测试代码如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
    @Test
    public void testSumXX() throws Exception {
        Calculator cal = PowerMockito.spy(new Calculator());
        PowerMockito.doReturn(2).when(cal,"sumXX",anyInt(),anyInt());
        assertEquals(2, cal.callSumXX(1, 2));
    }
}

注:因为@spy使用的真实的Calculator对象实例,调用的都是真实的方法,所以通过这种方式进行测试,在进行sonar覆盖率统计时统计出来的Calculator类覆盖率为50%.

通过如上的分析,通过spy的方式可以隔离环境依赖又能统计出sonar覆盖率,解决了一直依赖困扰着的问题。

以上是经验总结,如有问题可以一起探讨。

附:引用的PowerMock版本

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.6</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.6.6</version>
    <scope>test</scope>
</dependency>
  • 12
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值