背景
基础知识
mockito单元测试:它的做法是mock掉当前类的所有外部依赖,保障自己的代码没有问题。举个例子,如果数据库查询的语句出了问题,单元测试不会测试出来。因为它直接mock掉了,不会去真的去查数据库。从这点来说,好像有点说不过去。但是吧,仅从代码的角度来说,又好像并没有什么问题。因为它目标是保障自己的代码正常,sql不算。再说除了单元测试,还测试用例不是。
编写单元测试的流程:写单元测试的时候,需要逐行分析代码。如果是外部依赖,那么mock掉它,自己模拟一个结果作为替代。否则继续分析下一行,直到代码结束。最后校验在指定的输入下,输出的结果是否符合预期。
为什么需要mock当前类的私有方法?
首先,当我们自动生成单元测试类的时候,它只会为我们创建公共方法的测试方法。
当被测试类的一个公共方法调用它的私有方法时,单元测试就需要为私有方法里面的内容,也进行逐行分析mock。特别的,如果有另一个公共方法也调用了这个私有方法,那个这个公共方法也需要做同样的事情。明显,从测试覆盖来说,这个私有方法已经被覆盖,没必要再逐行mock一次。这时候,如果能mock掉这个私有方法就好了,对吧!
举个例子
创建被测试类
调用的私有方法分为“有返回”和“没有返回”两种。分别创建了pubFunction1调用带返回的私有方法,pubFunction2调用不带返回的私有方法。
package com.aliyu.service.demo.mock;
/**
* 描述:单元测试如何mock当前类的其他私有方法调用
* <p>作者: aliyu
* <p>创建时间: 2023-01-10 10:57 下午
*/
public class MockitoDemo {
/**
* 模拟一个公共方法调用"不带返回"的私有方法
*/
public void pubFunction1(){
System.out.println("开始调用公共方法");
withoutReturn();
System.out.println("结束调用公共方法");
}
/**
* 模拟一个公共方法调用"带返回"的私有方法
*/
public void pubFunction2(){
System.out.println("开始调用公共方法");
withReturn();
System.out.println("结束调用公共方法");
}
private void withoutReturn(){
System.out.println("调用了'不带'返回的私有方法");
}
private String withReturn(){
System.out.println("调用了'带'返回的私有方法");
return "AAA";
}
}
创建测试类
不带返回的私有方法mock
注:还需要注意的是,必须是junit4,否则会报错。在后面会提到。
完整代码如下:
package com.aliyu.service.demo.mock;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* 描述:单元测试如何mock当前类的其他私有方法调用
* <p>作者: aliyu
* <p>创建时间: 2023-01-11 1:40 上午
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(MockitoDemo.class)
public class MockitoDemoTest {
@InjectMocks
private MockitoDemo mockitoDemo;
@BeforeEach
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
/**
* 测试公共方法调用不带返回的私有方法
* doNothing实现(暂不清楚和doAnswer的区别,倾向于使用doNothing)
*/
@Test
public void testPubFunction1() {
MockitoDemo mockitoDemo1 = PowerMockito.spy(mockitoDemo);
try {
PowerMockito.doNothing().when(mockitoDemo1,"withoutReturn");
} catch (Exception e) {
e.printStackTrace();
}
mockitoDemo1.pubFunction1();
}
/**
* 测试公共方法调用不带返回的私有方法
* doAnswer实现
*/
@Test
public void testPubFunction3() {
MockitoDemo mockitoDemo1 = PowerMockito.spy(mockitoDemo);
try{
Answer answer=new Answer(){
public Object answer(InvocationOnMock invocationOnMock) throws Throwable{
return null;
}
};
PowerMockito.doAnswer(answer).when(mockitoDemo1,"withoutReturn");
}catch(Exception e){
e.printStackTrace();
}
mockitoDemo1.pubFunction1();
}
}
执行查看结果:
注:可以看到没有输出"调用了’不带’返回的私有方法"字样,说明已经成功mock。
带返回的私有方法mock
与不带返回的私有方法差别只在于mock时用的方法。
执行查看结果:
注:可以看到没有输出"调用了’带’返回的私有方法"字样,说明已经成功mock。
其他
如果用不是junit4,而是junit5会报错
大致的意思就是公有方法没有返回值,不能打一个有返回值的桩。明明我是为有返回的私有方法打桩的咧。
带返回值时doReturn必须在前面,否则mock失败
注:就好像如果不行doReturn声明返回值的话,它就会先去执行一下私有方法。。