淘宝导航里的链接网站怎么做,丹东网站优化,深圳网页设计师公司,请问如何做网站文章目录 Mockito单元测试 为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法#xff0c;自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(… 文章目录 Mockito单元测试 为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(加上参数)调用的次数使用Mock注解生成模拟对象疑惑心得。 注意自测的方法传递的参数会对打桩产生影响什么叫做打桩以及什么情况下需要打桩什么情况下不需要打桩打桩的时候返回不同的结果单测的结果可能不同上次的编译可能会影响以后的代码执行 公司使用Mockito单测的格式规范我们单测的方法该怎么写 真实方法单测方法需要注意的一些细节真实方法也会使用我们模拟的返回值 assert关键字的作用any()匹配器如果要用那么所有的参数都需要用测试的实际方法在模拟调用的时候一定要有参数不能写成any()打桩的时候到底需不需要模拟返回值进行单测前需要考虑什么需要单测的方法调用了其它A方法我们只需要考虑A方法中最后一个打桩的模拟数据即可工具类该如何打桩也即是模拟调用工具类里面的静态方法其实是模拟调用静态方法不用使用verify()方法后面不用方法的返回值就把方法直接去掉不需要打桩不需要打桩的情景可以直接在方法的最外部进行打桩原始方法所用到的所有的对象都需要在模拟方法对应的类里面使用Mock注解一下为了使真实方法中可以找得到这个模拟对象要不然会出现空指针异常查看覆盖率使用jacoco在浏览器查看覆盖率的方法 引入jacoco插件坐标引入mockito的坐标在Mockito单元测试的配置文件中对写好的单元测试类进行配置输入maven命令浏览器打开index.html的效果特别注意一个容易出错的点 通过jacoco生成的单测视图总结打桩规则除了打桩when和verify不要使用any()参数匹配器模拟构造器使用any()参数匹配器不能代替基本类型只能代替对象类型否则会报空指针错误原方法中后续如果用不到它的返回值我们可以不用打桩可以什么都不用做模拟的类一定要进行close掉 Mockito单元测试 为什么要使用Mock? 比如你现在想要测试一个方法是否是正常的但是这个方法中有很多调用数据库的代码那么我们就可以在每个调用数据库的地方打桩模拟一下访问完数据库之后的返回值这样我们就可以在测试的时候避免访问数据库了可以非常高效地完成我们的单元测试已达到验证我们写的方法到底对不对的目的。 先试想一个这样的场景如果想要模拟一个人被车撞之后会出现什么样的运动轨迹那我们要做实验的时候肯定是不能用一个活生生的人做实验的对不对 我们的Mock模拟对象也是一样的因为真实对象由于一些原因很难被拿来直接做测试所以我们就必须要模拟一个和真实对象一样的对象那这个模拟的对象做测试而Mock就是用来模拟对象的。 那么对象在什么时候是不方便被直接拿来做实验的啊你比如 真实对象的行为很难触发例如网络错误;真实对象速度很慢例如一个完整的数据库在测试之前可能需要初始化 导入依赖 我们的Mockito单元测试需要配合Junit单元测试一起使用因此首先我们需要导入这两个依赖如下图 dependencies!--导入Mockito单元测试依赖--dependencygroupIdorg.mockito/groupIdartifactIdmockito-all/artifactIdversion1.9.5/versionscopetest/scope/dependency!--导入junit单元测试依赖--dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.11/versionscopetest/scope/dependency
/dependenciesimport导入包 使用Mock模拟测试某个类中的某个方法是否可以成功执行
如果我们想要测试某个类中的某个方法是否可以执行我们不用直接调用这个类的这个方法我们可以模拟一下这个类让模拟的对象调用这个方法然后再去检验一下这个模拟对象是否成功的调用到了这个方法只要这个模拟对象成功调用到了这个方法那么就说明我们真实类中的这个方法是可以被成功执行的。这就是使用mockito来进行某个类的单元测试如下图 /*** 通过mock模拟一个对象然后检验这个对象的某个方法是否可以执行* */
Test
public void test1(){//模拟创建一个List对象List mock mock(List.class);//使用mock模拟出来的List对象,让这个对象添加一个元素1,(我们其实是为了验证List类中的add方法是否正常)mock.add(1);//验证模拟的对象List的add(1)方法是否执行如果正常发生了说明List类中的add(1)方法是正常的。这样我们的单元测试就算通过//verify()的作用主要是检验我们模拟出来的这个对象中的方法是否成功执行如果成功执行控制台什么信息都没有如果没有成功//执行控制台会报错误信息verify(mock).add(1);
}使用Mock模拟某个类的方法自己给这个方法返回我们指定的值
我们在测试一个控制器中的方法的时候这个控制器中肯定是有一些方法是需要访问数据库的但是我们自己在进行单元测试的时候其实不必访问数据库我们只需要知道访问数据库之后得到的这个值是什么所以我们就可以使用Mock来模拟出访问数据库的方法返回的值下面的这个例子就是我们自己给某个类中的方法直接指定一个返回值如下图 /*** 模拟对象中的某个方法给这个方法指定一个返回值那么我们再执行这个模拟对象的方法的时候返回的值就不再是真实* 对象返回的值而应该是我们自己设置的返回值。** 比如我们这里有一个Iterator迭代器原本调用迭代器对象的next()方法之后返回的值是集合中的下一个元素我们这里来模拟* 这个方法的返回值模拟的是第一次调用next()方法返回值是hello,第二次调用next()方法返回值是world,第三次以及往后调用* next()方法返回值是abc** 使用到了when(),thenReturn()方法第一个thenReturn()代表第一次执行iterator.next()方法的返回值是hello* 第二个thenReturn()代表第二次执行iterator.next()方法的返回值是world,* 第三个thenReturn()代表第三次即以后执行iterator.next()方法的返回值都是abc** 还是用到了assertEquals(猜想值,变量)断言方法* */
Test
public void test2(){//使用mock模拟出一个Iterator类Iterator iterator mock(Iterator.class);//自己设置迭代器对象方法next()的返回值when(iterator.next()).thenReturn(hello).thenReturn(world).thenReturn(abc);//使用mock模拟的iterator对象去看看iterator调用next()方法之后的返回值是否是我们想的那样String result iterator.next() iterator.next() iterator.next() iterator.next();//使用断言验证猜想的结果是否正确assertEquals(hello world abc abc,result);
}使用Mock模拟某个方法调用后会抛出指定的异常 /*** 使用Mock模拟对象规定某个方法要抛出一个异常* */
Test(expected IOException.class)
public void test3() throws IOException {OutputStream outputStream mock(OutputStream.class);//我们自己规定当执行OutputStream对象的close()方法的时候会主动的抛出一个IOException异常doThrow(new IOException()).when(outputStream).close();outputStream.close();
}使用Mock模拟测试某个类中的某个方法(加上参数)调用的次数 /*** 模拟类中的某个方法(加上对应的参数)调用的次数** times(次数)表示调用几次* never()表示从没有调用过* atLeastOnce()表示至少调用多少1次* atLeast(次数)表示至少调用n次* atMost(次数)表示最多调用n次* */
Test
public void test5(){List list mock(List.class);list.add(1);list.add(2);list.add(2);list.add(3);list.add(3);list.add(3);//验证是否被调用一次等效于下面的times(1)verify(list).add(1);verify(list,times(1)).add(1);//验证是否被调用2次verify(list,times(2)).add(2);//验证是否被调用3次verify(list,times(3)).add(3);//验证是否从未被调用过verify(list,never()).add(4);//验证至少调用一次verify(list,atLeastOnce()).add(1);//验证至少调用2次verify(list,atLeast(2)).add(2);//验证至多调用3次verify(list,atMost(3)).add(3);
}使用Mock注解生成模拟对象 /*** Date 2021/11/10 15:47* Author 望轩** 使用Mock注解生成一个模拟对象注意这样的话必须要在加上一个注解RunWith(MockitoJUnitRunner.class)* 要不然的话应用到的mockList或者是iterator会是null值*/
RunWith(MockitoJUnitRunner.class)
public class MockitoTest2 {Mockprivate List mockList;Mockprivate Iterator iterator;Testpublic void test1(){mockList.add(1);verify(mockList).add(1);}Testpublic void test2(){iterator.next();verify(iterator).next();}
}疑惑心得。
注意自测的方法传递的参数会对打桩产生影响
我们打桩其实是在真实方法的内部对应的位置进行打桩的如果真实方法的对应的真实代码不会执行那么我们在单测的时候打桩就无效。你比如说我们现在想要在真实方法的if判断体里面打一个桩如果这个if判断体一直不成立我们我们在单元测试方法中打的桩就不会替换掉真实代码中的具体位置。解释过程如下图 下图这个异常可以通过上图来解答 什么叫做打桩以及什么情况下需要打桩什么情况下不需要打桩
打桩其实就是在真实代码的地方用一个模拟方法代替然后真实方法执行到这个地方的时候它的返回值是我们模拟的返回值。when().thenReturn(),用这句代码我们可以自己给某个方法设定返回值这就叫做打桩。
在什么时候需要打桩呢如果我们想要自测的方法有返回值我们需要打桩如下图 什么时候不需要打桩呢当我们想要测试的方法没有返回值的时候这个时候我们就不用打桩了但是我们需要检测一下这个方法是否执行了如下图 打桩的时候返回不同的结果单测的结果可能不同
比如现在有一个需求就是我们在增加期间的时候数据库中不能存在这个期间要不然就增加失败在真实方法中的代码表现如下图 单测的代码如下图 上次的编译可能会影响以后的代码执行 我们提示的异常信息上面还有一个LocalDateTime日期类但是我们之前明明已经把我们的LocalDateTime日期类改成了Date日期类那么还报我们在项目中使用了LocalDateTime日期类这是为什么呢可能是因为我们的工程没有重新编译我们现在使用的还是之间没有改成Date的字节码所以才会出现上面的异常。这个时候我们要做的就是把Parent父工程重新clean一下然后在重新运行我们的单元测试方法。
clean完parent父工程之后重新测试单测方法执行成功。
公司使用Mockito单测的格式规范
首先我们的单测代码都是写在deploy工程的test包下面的如下图 我们写的单测类必须要继承一个类并且也要使用到一个注解如下图 我们单测的方法该怎么写
比如我们举一个例子我们举一个测试真实方法的例子。
真实方法
首先来看一下我们真实的方法是什么样子的如下图 单测方法
然后我们再来看一下我们单测的方法是什么样子的如下图 需要注意的一些细节
如下图 总之就是我们单测方法里面的模拟返回值必须要符合真实方法中的逻辑要不然真实方法会报异常我们的单测就不能通过。
真实方法也会使用我们模拟的返回值
有的时候真实方法中也需要用到我们的单测方法中模拟出来的返回值如下图 assert关键字的作用
assert关键字可以终止程序正常运行assert关键字的作用是断言如果它发现后面是true,那么程序可以正常运行但是如果它发现后面是false,那么它会主动抛出一个异常并终止正在运行的程序。
any()匹配器如果要用那么所有的参数都需要用
打桩的时候如果给一个参数用了匹配器any(),那么其它的参数也必须都用any()匹配器如下图: 测试的实际方法在模拟调用的时候一定要有参数不能写成any()
首先为什么会有单测主要是因为我们程序不想要访问数据库所以我们就可以模拟一下访问数据库的操作。
单测的时候调用我们要测试的方法的时候一定要有实际的参数如下图 打桩的时候到底需不需要模拟返回值
单测的时候如果我们想要打桩的地方它的返回值会被其它地方用到并且它的返回值的某个属性如果没有或者格式不正确还会出现异常那么这个时候我们就一定要打桩模拟一个返回值如下图 如果打桩的时候不需要返回值我们可以这样写如下图 不需要返回值也可以使用doNothing(),如下图 进行单测前需要考虑什么
在进行单测的时候先把我们这个方法所用到的数据库里面的数据写在一张纸上面成功写下所有的模拟数据之后再进行单测代码的编写。 在进行单测的时候首先要知道这个方法主要是干什么的比如我做的一个单测导入功能首先我需要先清楚导入这个方法需要从数据库里面查询的数据格式。比如这里从数据库里查询的数据格式有部门树和科目树所以我们就模拟了两个部门对象一个是一级部门另外一个是二级部门如下图 然后打桩的时候直接返回这些模拟数据如下图 然后模拟了三个科目分别是一级二级三级科目并且在打桩的时候直接返回模拟数据如下图 并且如果这些模拟对象存在某种逻辑关系我们也要指明比如在部门树里一级部门就必须是二级部门的父级如下图 在科目树里我们也指明了它们的关系如下图 需要单测的方法调用了其它A方法我们只需要考虑A方法中最后一个打桩的模拟数据即可
这里是导入方法importFromExcel()里面调用了getAllBudgetReportCategories(Long annualId),我们只需要关心这个方法需要返回什么数据给importFromExcel()方法才算合理就行了最后把这个合理数据模拟出来。所以这个方法的前两个地方打桩的时候它返回的模拟数据不用太多规范只要能保证后面能不报异常就行但是最后一个打桩的地方它返回的模拟数据必须要合理因为它返回的模拟数据会被importFromExcel()后面的部分用到所以所有打桩的模拟数据之间必须要相互匹配。
一个方法中如果有多个节点需要打桩我们只需要关心最后一个需要打桩的地方它的模拟数据至于前面需要打桩的地方它返回的模拟数据我们不需要关心但是要保证前面的这个打桩后的模拟数据能够保证后面能成功运行就行了。我们想一下我们调用这个方法的时候想要让这个方法返回什么数据那么在打桩的时候我们就模拟返回什么数据如下图 工具类该如何打桩也即是模拟调用工具类里面的静态方法其实是模拟调用静态方法 我们可以使用静态模拟类的方式进行打桩如下图 注意 如果工具类中的静态方法没有返回值我们直接模拟一下工具类就行了不需要对静态方法进行打桩如下图
不用使用verify()方法后面不用方法的返回值就把方法直接去掉不需要打桩 那像我们这种返回值不会被后面用到的方法在打桩的时候应该如何打桩呢像这种方法不用打桩我们直接去掉就行了。如下图 不需要打桩的情景
如果原本的方法中的访问数据库的方法后面不需要用到它的返回值那么我们可以不用打桩什么都不用写如下图 可以直接在方法的最外部进行打桩 打桩方法如下图 原始方法所用到的所有的对象都需要在模拟方法对应的类里面使用Mock注解一下为了使真实方法中可以找得到这个模拟对象要不然会出现空指针异常
对于原始的那个的哪个方法里面的所有的属性我们都需要Mock模拟一下因为你如果不模拟的话那么测试这个方法执行到这个对象的地方就会出现空指针异常因为我们单测的时候所有的对象都需要用模拟对象如果你没有用模拟对象就会出现空指针异常如下图 在单测方法所对应的那个类中没有引入模拟对象EnvUtils,如下图 然后对应的真实方法的地方牵涉到envUtils对象的地方就会报空指针异常如下图 查看覆盖率
第一步打开mvn如下图 第二步输入mvn命令如下图
mvn clean test org.jacoco:jacoco-maven-plugin:0.8.0:prepare-agent install -Dmaven.test.failure.ignoretrue 第三步执行之后去deploy-target-site-jacoco-resources-index.html查看在浏览器打开index.html页面可以查看覆盖率。 使用jacoco在浏览器查看覆盖率的方法
引入jacoco插件坐标
要想要使用jacoco在线生成覆盖率首先需要在pom.xml文件中引入jacoco插件如下图 buildplugins!-- 单测覆盖率--plugingroupIdorg.jacoco/groupIdartifactIdjacoco-maven-plugin/artifactIdversion0.8.0/versionexecutionsexecutiongoalsgoalprepare-agent/goal/goals/executionexecutionidreport/idphasetest/phasegoalsgoalreport-aggregate/goal/goals/execution/executionsconfigurationpropertyNamesurefireArgLine/propertyNameexcludesexclude**/model/*/excludeexclude**/model/**/excludeexclude**/dto/*/excludeexclude**/dal/**/excludeexclude**/copy/*/excludeexclude**/util/*/excludeexclude**/utils/**/excludeexclude**/task/**/excludeexclude**/constant/*/excludeexclude**/*Config.class/excludeexclude**/*Util.class/excludeexclude**/*Exception.class/excludeexclude**/*Enum.class/excludeexcludecom/timevale/budget/service/mq/MqConsumer.class/excludeexcludecom/timevale/budget/service/impl/ExcelServiceImpl.class/exclude/excludes/configuration/plugin/plugins
/build把build标签写在denpendencies的下面就行了。
引入mockito的坐标
使用mockito写单测的时候我们需要先引入mockito的坐标如下图 !-- 单元测试--
dependencygroupIdorg.mockito/groupIdartifactIdmockito-core/artifactIdversion3.6.28/versionscopetest/scope
/dependency
dependencygroupIdorg.mockito/groupIdartifactIdmockito-inline/artifactIdversion3.11.2/versionscopetest/scope
/dependency在Mockito单元测试的配置文件中对写好的单元测试类进行配置
注意一定要在配置文件中对自己写的单元测试类进行配置否则的话在index.html页面看不到我们单元测试类的覆盖率。
输入maven命令
在maven工具中输入下面的命令
mvn clean test org.jacoco:jacoco-maven-plugin:0.8.0:prepare-agent install -Dmaven.test.failure.ignoretrue 结果如下图 浏览器打开index.html的效果 特别注意一个容易出错的点
我这里的工程是buget工程这个工程存放在我本地的电脑中了特别注意存放这个工程的目录不能含有中文必须要是全英文要不然的话在浏览器中打开index.html文件的时候会显示覆盖率为0。
以后只要是本地电脑存放工程的目录都必须要是全英文的防止出现一些奇怪的错误记住这个规范如下图 通过jacoco生成的单测视图总结打桩规则
单测一个方法的时候首先去分析这个方法需要使用那些模拟数据然后在分析有哪几个地方需要进行打桩我们直接在打桩的时候返回这些模拟数据就行了如下图 除了打桩when和verify不要使用any()参数匹配器 模拟构造器
当我们打桩的时候构造器会先执行然后再打桩所以我们一定要先模拟一下构造器不让它执行如下图
使用any()参数匹配器不能代替基本类型只能代替对象类型否则会报空指针错误 原方法中后续如果用不到它的返回值我们可以不用打桩可以什么都不用做 上图中我们就可以把左边的那个打桩给去掉单元测试仍然能够执行成功。
模拟的类一定要进行close掉
对于我们模拟的类一定要对它进行close不管我们模拟的是工具类还是模拟的其它的什么类在执行完真实的方法之后一定都要close一下否则的话后面再模拟这个类的时候会出错。一定要在执行完真正的业务方法之后再进行close否则的话在没有执行真正的业务方法之前进行close方法的调用就相当于是没有模拟。 如下图 如果没有close掉模拟的对象后面的方法再次模拟这个类的时候会报错如下图