当需要对静态类进行mock的时候:mockito-core的版本要在3.4以上,还要引入mockito-core依赖的其他jar,要引入mockito-inline,junit包要放在mockito-inline之前,引入的时候如果报错,请检查maven的setting文件,配置的仓库路径是否能正常下载、
org.springframework.boot
spring-boot-starter-web
3.0.4
org.springframework.boot
spring-boot-starter-test
2.3.9.RELEASE
org.mockito
mockito-junit-jupiter
org.mockito
mockito-core
org.mockito
mockito-junit-jupiter
4.5.1
test
org.junit.jupiter
junit-jupiter-api
test
junit
junit
test
org.mockito
mockito-core
3.9.0
test
org.mockito
mockito-inline
4.5.1
test
net.bytebuddy
byte-buddy
1.10.22
test
net.bytebuddy
byte-buddy-agent
1.10.22
test
1、检查@ComponentScan 是否正常扫描到了路径
2、设置idea-file-project structure-moudles-选中模块-Sources-将test下面的java文件夹路径设置为tests(选中java点击tests)
3、选中要测试的service,右键-generate-选择test-
选择Junit的版本、测试名类称、路径(最好不要改了,与service的位置一致),选择要测试的方法
4、测试覆盖率配置
当写完测试类debug一下之后,edit Config....
选中测试类然后选class、选中下面红色的第一个,然后点-删去,点+添加进第二个,然后点击上图框住的小按钮,就可以查覆盖率了
@SpringBootTest()
@RunWith(SpringRunner.class)
方式一:
@InjectMock|@Mock:
@InjectMock:注释的是要测试的实现类,不是接口
@Mock:注释测试类serviceimpl用@Autowired引入的成员变量(mock后真实的方法不再调用)
但用Mockito.when(service.方法名(参数)).thenCallRealMethod();还是可以调真实的方法
@Spy:注释测试类serviceimpl用@Autowired引入的成员变量(spy真实的调用不调用要看写法)
但用Mockito.doReturn("不执行此方法").when(service).方法名(参数);还是可以不调用真实的方法
@Spy 会真实的执行对象的方法(如果方法报错,test直接报错)
@Mock 不会执行对象的方法(即使方法报错,test只会使用你设置的返回值,不影响流程)
方式二:
@Autowired| ReflectionTestUtils.setField();
@Autowired注释被注入mock的被测试的类
AopTestUtils.getTargetObject()、AopTestUtils.getUltimateTargetObject()
ReflectionTestUtils.setField();将其他的mock对象注入被测试的类中
@Autowired和@InjectMock最好不要一起使用,如果一起使用了
a、必须在test之前@Before中执行 MockitoAnnotations.openMocks(this);对mock初始化
b、测试的时候要用this.serviceimpl.方法名()测试 否则mock还会走真实的方法
需要手动再注入一下,不建议使用
ReflectionTestUtils.setField();
Student student=Mockito.mock(Student.class);
Student student=Mockito.spy(Student.class);
当方法实际传入的参数如果是null,则设置的mock的返回值会不生效,所以传入的参数Mockito.when(service.方法名(Mockito.anyString())).thenReturn(要返回的值);
service.方法名(null); //name上面的返回值失效了
Mockito.when(service.方法名(参数)).thenReturn(要返回的值); Mockito.when(service.方法名(参数)).thenCallRealMethod(); Mockito.when(service.方法名(参数)).thenThrow(new RuntimeException()); Mockito.doNothing().when(service).方法名(参数); Mockito.doReturn("不执行此方法").when(service).方法名(参数); new 对象的:MockedConstruction 静态方法:MockedStatic
1、mock 通过@Autowired注入的对象的方法(有返回值、无返回值)
2、mock 通过new的对象的方法
3、mock 调用的静态方法(有返回值、无返回值)
4、mock 同一个类的静态方法、私有方法、非私有方法
5、通过反射的方式测试私有方法
public class Util {
public static String getNum(){
int i=1/0;
return "123";
}
public static void skipNum(){
int i=1/0;
}
}
public class Sertn {
public String setInedx(String shh ){
int i=1/0;
return "haha";
}
public void setInedxVoid(String shh ){
int i=1/0;
}
private String getIndex(){
int i=1/0;
return "private";
}
}
package com.springcloud.my.stock.service.impl;
import com.springcloud.my.stock.bean.Student;
import com.springcloud.my.stock.service.MyClassService;
import com.springcloud.my.stock.service.MyTestService;
import com.springcloud.my.stock.service.StudentService;
import com.springcloud.my.stock.util.Sertn;
import com.springcloud.my.stock.util.Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyClassServiceImpl implements MyClassService {
@Autowired
private StudentService studentService;
@Override
public String doHomeWork(String name) {
//有返回值
String result= studentService.doHomeWork(name);
Student student=new Student();
student.setName(name);
String result2= studentService.doHomeWork2(name,student);
//无返回值
studentService.doMathHomeWork();
return result+"MyClassService"+result2;
}
/***静态方法 和new方法**/
@Override
public String getNumber() {
studentService.doMathHomeWork();
Util.skipNum();
String num=Util.getNum();
Sertn sertn=new Sertn();
String hh=sertn.setInedx("");
sertn.setInedxVoid();
return num+hh;
}
/***自己类里面的方法**/
@Override
public String getOwnNumber() {
studentService.doMathHomeWork();
String gethahaha=getHaHa();
String gethehehe=getHeHe();
getTranslation();
return gethahaha+gethehehe;
}
public void getTranslation(){
int i=1/0;
System.out.println("MyClassService getTranslation");
}
public String getHaHa(){
int i=1/0;
return "MyClassService haha";
}
private String getHeHe(){
int i=1/0;
return "hehe";
}
}
package com.springcloud.my.stock.service;
import com.springcloud.my.stock.bean.Student;
import com.springcloud.my.stock.service.impl.MyClassServiceImpl;
import com.springcloud.my.stock.util.Sertn;
import com.springcloud.my.stock.util.Util;
import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest()
@RunWith(SpringRunner.class)
public class MyClassServiceTest {
@InjectMocks
//spy标签是因为要对MyClassServiceImpl 非测试的其他的方法进行mock
@Spy
private MyClassServiceImpl myClassService;
/**如果是@Mock那么doReturn和thenReturn都不会执行真正的方法,
* 如果是@Spy 那么doReturn不会执行真正的方法,thenReturn会执行真正的方法**/
/**
* 在这里Mock的成员变量如果不在下面设置返回值,返回的结果是返回类型的空值
*/
@Mock
private StudentService studentService;
private AutoCloseable closeable;
@Spy
private MyClassServiceImpl myClassServiceSpy;
@Before
public void init() {
closeable= MockitoAnnotations.openMocks(this);
/***
* MyClassServiceImpl 上的注解如果是@Autowired 而不是@InjectMocks 需要用下面的代码手动的注入
* MyClassServiceImpl myClassService1= AopTestUtils.getTargetObject(myClassService);
* ReflectionTestUtils.setField(myClassService1, "studentService",studentService);
*/
}
@After
@SneakyThrows
public void afterProject() {
closeable.close();
}
@Test
public void doHomeWorkTest() {
//正常的测试 String result=myClassService.doHomeWork("张三");
// 返回值 StudentService张三MyClassService张三
//mock后
String result=myClassService.doHomeWork("张三");
Assert.assertEquals(result,"nullMyClassServicenull");
/**无返回值的方法 可以直接跳过**/
Mockito.doNothing().when(studentService).doMathHomeWork();
/**如果studentService.doHomeWork()的参数是123 返回设置的返回值且不执行该方法***/
Mockito.doReturn("不执行此方法").when(studentService).doHomeWork("123");
Mockito.doReturn("不执行此方法111").when(studentService).doHomeWork("456");
result=myClassService.doHomeWork("张三");
Assert.assertEquals(result,"nullMyClassServicenull");
result=myClassService.doHomeWork("123");
Assert.assertEquals(result,"不执行此方法MyClassServicenull");
result=myClassService.doHomeWork("456");
Assert.assertEquals(result,"不执行此方法111MyClassServicenull");
/**when thenReturn的写法***/
Mockito.when(studentService.doHomeWork("456")).thenReturn("可能执行");
result=myClassService.doHomeWork("456");
Assert.assertEquals(result,"可能执行MyClassServicenull");
/***无论studentService.doHomeWork()的参数是什么,都返回设定的值且不执行该方法**/
Mockito.doReturn("不执行此方法").when(studentService).doHomeWork(Mockito.anyString());
result=myClassService.doHomeWork("张三");
Assert.assertEquals(result,"不执行此方法MyClassServicenull");
/***当方法有多个参数时,参数必须都是Mockito. 的,或者都不是Mockito. 的 ,具体值的参数要用Mockito.eq包起来***/
/*****不论传入的*****/
Mockito.doReturn("*****").when(studentService)
.doHomeWork2(Mockito.eq("李四"),Mockito.any());
Mockito.doReturn("XXXXX").when(studentService)
.doHomeWork2(Mockito.eq("李五"),Mockito.any());
result=myClassService.doHomeWork("张三");
Assert.assertEquals(result,"不执行此方法MyClassServicenull");
result=myClassService.doHomeWork("李四");
Assert.assertEquals(result,"不执行此方法MyClassService*****");
result=myClassService.doHomeWork("李五");
Assert.assertEquals(result,"不执行此方法MyClassServiceXXXXX");
/***如果参数是对象***/
Mockito.when(studentService.doHomeWork2(Mockito.any(),Mockito.any())).thenAnswer(mock->{
/**1表示取方法的第一个参数**/
Student student=mock.getArgument(1);
if(student.getName().equals("哈哈")){
return "Student";
}else{
return "";
}
});
result=myClassService.doHomeWork("哈哈");
Assert.assertEquals(result,"不执行此方法MyClassServiceStudent");
result=myClassService.doHomeWork("111");
Assert.assertEquals(result,"不执行此方法MyClassService");
}
//test的包要引入 import org.junit.Test;
@Test
public void getNumberTest() {
//静态方法
//无返回值的静态方法不需要处理直接就会跳过
MockedStatic utilMockedStatic=Mockito.mockStatic(Util.class);
//new 对象的方法
//无返回值的方法不需要处理直接就会跳过
MockedConstruction sertnMockedConstruction=
Mockito.mockConstruction(Sertn.class,((mock,context)->{
Mockito.doReturn("baba").when(mock).setInedx(Mockito.anyString());
}));
/**无返回值的方法 可以直接跳过**/
Mockito.doNothing().when(studentService).doMathHomeWork();
try{
utilMockedStatic.when(()->Util.getNum()).thenReturn("000");
String result=myClassService.getNumber();
Assert.assertEquals(result,"000baba");
//有返回值的静态方法
}finally {
//一定要关了。否则多个test会报错,
//因为相同的类的MockedStatic、MockedConstruction一个线程只能有一个
utilMockedStatic.close();
sertnMockedConstruction.close();
}
}
@Test
public void getOwnNumberTest(){
/***给myClassService加上 @Spy标签**/
Mockito.doReturn("baba").when(myClassService).getHaHa();
Mockito.doNothing().when(myClassService).getTranslation();
String result=myClassService.getOwnNumber();
//验证方法至少调用过一次
verify(myClassService,atLeastOnce()).getHaHa();
Assert.assertEquals(result,"000baba");
}
//测试私有方法
@Test
@SneakyThrows
public void getHeHeTest(){
//如果只是单纯的测试私有方法可以通过反射
//如果想mock 私有方法,目前没有合适的方式 否则参考powermockito框架吧
Method privateMethod =
MyClassServiceImpl.class.getDeclaredMethod("getHeHe", null);
privateMethod.setAccessible(true);
String result= (String) privateMethod.invoke(MyClassServiceImpl.class.newInstance(),null);
//验证返回值是否一致
Assert.assertEquals(result,"babahaha");
}
}