做公司网站哪家好重庆九龙坡区,wordpress怎么分段,学生个人网页设计作品模板,网站最近不收录文章目录 一、什么是Mock1、Mock定义2、为什么使用3、常用的Mock技术4、Mokito中文文档5、集成测试和单元测试区别 二、API1、Mockito的API2、ArgumentMatchers参数匹配3、OngoingStubbing返回操作 三、Mockito的使用1、添加Maven依赖2、InjectMocks、Mock使用3、SpringbootTes… 文章目录 一、什么是Mock1、Mock定义2、为什么使用3、常用的Mock技术4、Mokito中文文档5、集成测试和单元测试区别 二、API1、Mockito的API2、ArgumentMatchers参数匹配3、OngoingStubbing返回操作 三、Mockito的使用1、添加Maven依赖2、InjectMocks、Mock使用3、SpringbootTest 注解和 RunWith 注解在测试类的作用 四、Mock 测试代码案例1、添加依赖2、编写业务代码3、Mock 测试1常规测试2Mock 测试3Mock 测试常用方法thenReturn 系列方法thenThrow 系列方法verify 系列方法模拟对象有两种方式对 void 的方法设置模拟 4Mock 测试常用注解 五、Mock 测试结合 Java 反射综合案例 一、什么是Mock
1、Mock定义
Mockito是Java单元测试开发框架。在写测试单元时它可以MockMock的中文释义是模拟所以Mockito从名字上可以看出是要模拟一种场景。
它可以模拟任何 Spring 管理的 Bean、模拟方法的返回值、模拟抛出异常等避免为了测试一个方法却要自行构建整个 bean 的依赖链。
Mock 测试主要是用来进行开发中一些 未完成的接口 或者 网络断开、数据库连接错误 等方法调用。
举个例子
如下代码所示list 集合需要从数据库查询出来。但是如果暂时数据库不能用有需要测试这个时候就可以进行 Mock 模拟出符合条件的 list 集合进行本地测试无需连接数据库。 2、为什么使用
在对代码进行单元测试过程中经常会有以下的情况发生
class A 依赖 class B
class B 依赖 class C和class D
class C 依赖 ...
class D 依赖 ... 1.被测对象依赖的对象构造复杂
我们想对class A进行单元测试需要构造大量的class B、C、D等依赖造步骤多、耗时较长的对象
对于他们的构造我们可以利用mock去构造过程复杂的对象用于class A的测试
因为我们只是想测试class A的行为是否符合预期我们并不需要测试依赖对象。2.被测单元依赖的模块尚未开发完成而被测对象需要依赖模块的返回值进行测试
----- 比如service层的代码中包含对dao层的调用但dao层代码尚未实现
----- 比如web的前端依赖后端接口获取数据进行联调测试但后端接口并未开发完成
----- 比如数据库还不能正常使用但是需要测试功能逻辑是否可行。3、常用的Mock技术
PowerMockEasyMockMockitoJMock
目前在 Java 中主流的 Mock 测试工具有 Mockito、JMock、EasyMock 等等而 SpringBoot 目前内建的是 Mockito 框架。
4、Mokito中文文档
Mokito中文官网
5、集成测试和单元测试区别
1集成测试 测试过程中会启动整个Spring容器调用DB 或者 依赖的外部接口等。只不过访问的环境是测试环境。这个过程最大程度还原生产环境过程但是耗时长。
2单元测试 不启动整个应用只对单个接口/类进行测试。不调用DB 、外部接口依赖的服务都Mock掉只测试代码逻辑。这个过程测试用例耗时短。
二、API
1、Mockito的API
mock构建一个我们需要的对象可以mock具体的对象也可以mock接口spy构建监控对象verify验证某种行为when当执行什么操作的时候一般配合thenXXX 一起使用。表示执行了一个操作之后产生什么效果doReturn返回什么结果doThrow抛出一个指定异常doAnswer做一个什么相应需要我们自定义Answertimes某个操作执行了多少次atLeastOnce某个操作至少执行一次atLeast某个操作至少执行指定次数atMost某个操作至多执行指定次数atMostOnce某个操作至多执行一次doNothing不做任何处理doReturn返回一个结果doThrow抛出一个指定异常doAnswer指定一个操作传入AnswerdoCallRealMethod返回真实业务执行的结果只能用于监控对象
2、ArgumentMatchers参数匹配
anyInt任何int类型的参数类似的还有anyLong/anyByte等等。eq等于某个值的时候如果是对象类型的则看toString方法isA匹配某种类型matches使用正则表达式进行匹配
3、OngoingStubbing返回操作
thenReturn指定一个返回的值thenThrow抛出一个指定异常then指定一个操作需要传入自定义AnswerthenCallRealMethod返回真实业务执行的结果只能用于监控对象
三、Mockito的使用
1、添加Maven依赖
Java 环境依赖
!-- https://mvnrepository.com/search?qMockito--
dependencygroupIdorg.mockito/groupIdartifactIdmockito-core/artifactIdversion4.4.0/version
/dependencySpringBoot 环境依赖
注意SpringBoot 默认的 Mock 框架是 Mockito和 junit 一样只需要依赖 spring-boot-starter-test 就可以了
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId
/dependency2、InjectMocks、Mock使用
Mock: 用于代替Mockito.mock创建mock对象,创建一个Mock实例需要基于JUnit5环境。InjectMocks: 创建一个实例其余用Mock或Spy注解创建的mock将被注入到用该实例中。
直白的理解就是
如图实体类TUserServiceImpl通过注解 Autowired注入了三个实体TUserMapper、JdbcTemplate 和 NamedParameterJdbcTemplate。 如果想要测试TUserServiceImpl那么test中TUserMapper、JdbcTemplate 和 NamedParameterJdbcTemplate就要用Mock注解创建Mock实例而要被测试TUserServiceImpl就要用InjectMocks注解创建实例这个时候被Mock注解创建的TUserMapper、JdbcTemplate 和 NamedParameterJdbcTemplate就被注入到通过 InjectMocks注解创建的TUserServiceImpl实例中。如下图所示
最后的大白话解释
你要测试哪个类如TUserServiceImpl那么就用 InjectMocks注解 被测试的类中通过 Autowired注解注入了几个那么测试类里面就用Mock注解创建几个实例
使用Mockito的注解需要让注解生效让注解生效的方法有两个
给被测类添加 RunWith(MockitoJUnitRunner.class) 或者 RunWith(SpringJUnit4ClassRunner.class) 注解
RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {...
}在初始化方法中使用MockitoAnnotations.openMocks(this)
Before
public void init() {MockitoAnnotations.openMocks(this);
}注意新版spring-boot-starter-test不再集成junit而是junit-jupiter,找不到RunWith注解 spring-boot-starter-test 2.5.5 版本只需要在类上加上SpringBootTest即可不需要再加RunWith()注解了。spring-boot-starter-test 2.4.x 版本的也没有RunWith()注解至于从哪个版本开始没有RunWith()注解的请自行查阅相关文档。一些较低版本也没有 openMocks 方法而是 initMocks
3、SpringbootTest 注解和 RunWith 注解在测试类的作用
SpringbootTest
这个注解相当于启动类的作用加了这个注解后当使用加了Test注解的方法时会加载Spring上下文跟SpringbootApplication这个启动类一样把bean加载进IOC容器。
其中参数classes 需指明启动类.class如果不指明需要保证启动类所在的包和加了SpringbootTest注解的类 在同一个包或者是启动类的子包下,否则注入到 Autowired / Resource会报空指针异常。如下
SpringBootTest(classes MySpringbootApplication.class)RunWith
RunWithSpringRunner.class作用是与Spring环境整合因为在测试类中我们可以需要用Autowired自动装配IOC容器中的bean所以需要与Spring环境进行整合才能实现自动装配否则会装配失败导致bean为null。
有时候会发现有的测试类不添加RunWith也能注入成功这是因为如果导入Test注解的包是org.junit.jupiter.api.Test则不需要添加RunWith注解如果导入的是org.junit.Test,则需要添加这点需要注意。
四、Mock 测试代码案例
1、添加依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactId/dependency注意本案例用的 springboot 版本是 2.6 版本 2、编写业务代码
Service
public class PositionService {public String getStr(String str){return str;}public void getVoid(){System.out.println(没有返回值);}}3、Mock 测试
1常规测试
先不使用 Mockito 而是真的去调用一个正常的 Spring bean 测试类写法如下。其实就是很普通的注入 PositionService bean然后去调用他的方法。
测试代码
注意
可以看到测试类中引用的包是 org.junit.jupiter.api.Test 和 org.junit.jupiter.api.BeforeEach是 jupiter.api 包下面的此时测试类只用了 SpringBootTest 这一个注解
但是如果用的是 org.junit.Test 和 org.junit.Before测试类上面必须同时用 RunWith(SpringRunner.class) 和 SpringBootTest(classes MySpringbootApplication.class)。必须同时用
import com.cyd.applicationstartup.MySpringbootApplication;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest(classes MySpringbootApplication.class)
public class PositionServiceTest {Autowiredprivate PositionService positionService;BeforeEachpublic void init() {// 对所有注解了Mock的对象进行模拟MockitoAnnotations.openMocks(this);System.out.println(初始化方法);}Testpublic void testGetStr() {String str positionService.getStr(刘亦菲);System.out.println(测试结果 str);}
}测试结果 2Mock 测试
Mock 测试需要自定返回结果,结果和方法返回结果类型一致。
语法如下
Mockito.when( 对象.方法名() ).thenReturn( 自定义结果 )使用 Mockito 模拟 Bean 的单元测试代码示例如下
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest(classes MySpringbootApplication.class)
public class PositionServiceTest {Mockprivate PositionService positionService;BeforeEachpublic void init() {System.out.println(初始化方法);}Testpublic void testMockGetStr() {// 定义当调用mock positionService 的 getStr() 方法并且任意字符串参数时就返回字符串 刘亦菲Mockito.when(positionService.getStr(Mockito.anyString())).thenReturn(刘亦菲);// 定义当调用 mock positionService 的 getStr() 方法并且参数是字符串 美女 时就返回字符串 刘亦菲Mockito.when(positionService.getStr(美女)).thenReturn(刘亦菲);System.out.println(positionService.getStr(美女));// 验证 positionService 的 getStr()这个方法是否被调用过Mockito.verify(positionService).getStr(刘亦菲);}
}注意 代码中第一个 Mockito.when 的参数用的是 Mockito.anyString(),表示 任意字符串参数调用 getStr() 方法就会返回字符串 “刘亦菲” 第二个 Mockito.when 的参数用的是字符串美女表示限制只有当参数是 美女时才会返回 “刘亦菲”。 因此在日常 Mock 测试中通常使用 Mockito.any 作为参数。
3Mock 测试常用方法
thenReturn 系列方法
① 定义当调用mock positionService 的 getStr() 方法并且任意字符串参数时就返回字符串 “哈哈哈哈”
Mockito.when(positionService.getStr(Mockito.anyString())).thenReturn(哈哈哈哈);
System.out.println(positionService.getStr(任意参数));表示任意值的参数如下图 ② 定义当调用 mock positionService 的 getStr() 方法并且限制参数只有是字符串 “美女” 时才返回字符串 “刘亦菲”
Mockito.when(positionService.getStr(美女)).thenReturn(刘亦菲);
System.out.println(positionService.getStr(美女));thenThrow 系列方法
① 当调用 mock positionService 的 getStr() 方法输入的的参数是 字符串 “9” 时抛出一个 RuntimeException
Mockito.when(positionService.getStr(9)).thenThrow(new RuntimeException(mock throw exception));
String str positionService.getStr(9); //会抛出一个RuntimeExceptio测试结果 ② 如果方法没有返回值的话即是方法定义为 public void myMethod() {…}要改用 doThrow() 抛出 Exception
Mockito.doThrow(new RuntimeException(mock throw exception when method is void)).when(positionService).getVoid();
positionService.getVoid(); //会抛出一个RuntimeException测试结果 verify 系列方法
① 检查调用 positionService 的 getStr() 方法、且参数为 “3” 的次数是否为1次:
Mockito.verify(positionService, Mockito.times(1)).getStr(Mockito.eq(3));② 验证调用顺序验证 positionService 是否先调用 getStr() 两次并且第一次的参数是 “3”、第二次的参数是 “5”然后才调用 getVoid() 方法:
InOrder inOrder Mockito.inOrder(positionService);
inOrder.verify(positionService).getStr(3);
inOrder.verify(positionService).getStr(5);
inOrder.verify(positionService).getVoid();模拟对象有两种方式
对注解了 Mock 的对象进行模拟 MockitoAnnotations.openMocks(this);对单个对象手动 mock xxx Mockito.mock(xxx.class);
对 void 的方法设置模拟
positionService 中有如下方法
public void getVoidWithParam(String param){System.out.println(没有返回值);}Mock 测试方法 /*对void的方法设置模拟*/Mockito.doAnswer(invocationOnMock - {System.out.println(进入了Mock);return null;}).when(positionService).getVoidWithParam(param);4Mock 测试常用注解
全部 Mock
Mock
private ServiceA serviceA;这种方式serviceA中的所有方法都会被mock并不会真正被调用到
依赖注入
ServiceA 依赖了 ServiceC 和 DaoA使用InjectMocks可以自动注入。
InjectMocks
private ServiceA serviceA;真实调用
Spy
private ServiceC serviceC;这种方式调用serviceC的方法会被真实调用。
五、Mock 测试结合 Java 反射综合案例
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;RunWith(MockitoJUnitRunner.class)
public class MyMockServiceTest {Mockprivate CustomerDao customerDao;Mockprivate MockDaoA mockDaoA;Mockprivate MockDaoC mockDaoC;Mockprivate MockDaoD mockDaoD;Mockprivate MockDaoE mockDaoE;InjectMocksMyMockService myMockService;MockTestDataDto mockTestDataDto;Beforepublic void init() {// Apollo 配置ReflectionTestUtils.setField(myMockService, mockValue, 58699DFR-1456984524);MockitoAnnotations.initMocks(this);mockTestDataDto new MockTestDataDto();mockTestDataDto.setCallback(callback);PolicyRelatedInfo policyRelatedInfo new PolicyRelatedInfo();policyRelatedInfo.setRelationToAppnt(1);Mockito.when(mockDaoA.selectRelationByParams(Mockito.any())).thenReturn(policyRelatedInfo);Customer customer new Customer();insu.setPhone(4654);insu.setSex(1);insu.setIdType(1);insu.setIdNo(1);insu.setName(张三);insu.setBirthday(new Date());Mockito.when(customerDao.selectByPrimaryKey(Mockito.anyInt())).thenReturn(customer);}Testpublic void test() throws NoSuchMethodException, SecurityException, IllegalAccessException,IllegalArgumentException, InvocationTargetException, InstantiationException {ArrayListPolicyDanger getPolicyDangerList new ArrayList();PolicyDanger policyDanger1 new PolicyDanger();policyDanger1.setIsPassFlag(M);policyDanger1.setDanderCode(595648FD);policyDanger1.setTotalAmnt(new BigDecimal(100.1223));PolicyDanger policyDanger2 new PolicyDanger();policyDanger2.setIsPassFlag(M);policyDanger2.setDanderCode(595648FD);policyDanger2.setTotalAmnt(new BigDecimal(100.1223));getPolicyDangerList.add(policyDanger1);getPolicyDangerList.add(policyDanger2);Mockito.when(mockDaoC.selectPolicyDangerList(Mockito.any())).thenReturn(getPolicyDangerList);ArrayListProvince provinceList new ArrayList();Province province new Province();province.setProvinceCode(5894);province.setDutyCode(5928D2);provinceList.add(province);Mockito.when(mockDaoD.selectPolicyByQueryParam(Mockito.any())).thenReturn(provinceList);ArrayListUser userList new ArrayList();User user new User();user.setBuyDate(new Date());userList.add(user);Mockito.when(mockDaoE.selectUserByQueryParam(Mockito.any())).thenReturn(userList);// 反射获得类MyMockService hx new MyMockService();Class? extends MyMockService cls1 hx.getClass();// 通过指定方法名称和参数类型的方法来获取Method对象(注意: 如果方法名称不存在或参数类型不正确的话,会报错,不会返回null)// 注意这里测试的是 private 修饰的私有方法需要用 getDeclaredMethod// setUserInfo 是需要测试的方法名后面为该方法需要的参数类型Method method cls1.getDeclaredMethod(setUserInfo, MockTestDataDto.class, Integer.class, String.class,SimpleDateFormat.class);method.setAccessible(true);// 执行方法method.invoke(myMockService, mockTestDataDto, 1, 1, new SimpleDateFormat());}
}注意
如果测试的类中有如下配置 Value(${mock.mapping.name})private String mockValue;测试代码中需要如下设置配置值 ReflectionTestUtils.setField(mockService, mockValue, 58699DFR-1456984524);