当前位置: 首页 > 后端技术 > Java

突变测试

时间:2023-04-01 18:58:36 Java

有什么问题或者意见可以在评论区回复。欢迎大家一起讨论学习。1、什么是MutationTesting(以下简称MT)?通俗地说,UT的UTMT修改了部分源码,在修改后的源码上运行UT,然后对比修改前后的差异,检测UT是否覆盖各种场景。我自己的理解是对于一些写错的错误,比如>=错写成<=,UT不一定能盖住,但是MT可以盖住。最重要的是它可以提高UT的准确率,并且可以检测到即使UT覆盖了100%,一些逻辑判断仍然无法覆盖,更有效的降低了出现bug的概率。二、MT的原理1.判断大于等于大于等于,具体如下:原逻辑MT修改逻辑<<=<=<>>=>=>=>//源码if(a>>><<>>><org.pitestpitest-maven<版本>1.6。310**.*ITxmlhtmlsrc/test/resources/mutationHistorysrc/test/resources/mutationHistoryfalse/plugin>如果只修改部分代码,需要单独运行MT,在上面在配置中的配置中添加如下内容,可以指定MT单独运行某个类如果需要修改更严格的MT测试,可以在配置中添加如下内容,可以修改oilDEFAULTS,STRONGER,ALL,见https://pitest.org/quickstart...用于特定规则DEFAULTS执行命令运行MTmvnorg.pitest:pitest-maven:mutationCoverage在本地运行MT。如果代码UT和源码很多,会耗时较长,所以需要通过上面配置historyOutputFIle,每次执行后会生成一个历史文件,下次运行MT时,只有有源码的UT后期会运行代码修改,缩短每次执行时间。具体截图如下,内容为4。运行后报告绿色显示已经通过MT的覆盖,红色表示未覆盖。正常情况下,我们自己写UT的时候应该默认覆盖(KILLED)。如果没有被覆盖,则显示(SURVIVED)//源码publicStringtestMT(Stringcode){if(code.equals("1")){return"SUCCESS";}return"FAIL";}//UT@TestpublicvoidtestMT(){Assert.assertEquals("SUCCESS",mtDemo.testMT("1"));Assert.assertEquals("FAIL",mtDemo.testMT("2"));}如果在某些逻辑情况下抛出XXException,需要在测试注解中添加如下内容,也可以覆盖MT@Test(预期=XXException.class)源码并尽量返回有意义的结果,避免使用void,返回void时,MT强行注释掉的情况,无论如何都无法通过assertion判断(其实我感觉这种情况是模拟的时候写代码,完成写void的方法后,忘记写在main方法中调用了)。//明确的返回可以断言判断Assert.assertEquals("SUCCESS",mtDemo.testMT("1"));如果if判断有多个条件,mock的返回需要覆盖最后一个判断,支付如下图param2为1,但是param1不匹配的时候会通过,MT认为main的覆盖率不够,修改UT后,增加另一种情况,param1匹配,param2不匹配,完美覆盖,MT表示Kill,提示覆盖完成//源代码publicStringtestIf(Stringparam1,Stringparam2){if("1".equals(param1)||"1".equals(param2)){返回"SUCCESS";}else{返回“失败”;}}//UT@TestpublicvoidtestIf(){Assert.assertEquals("SUCCESS",mtDemo.testIf("0","1"));}@TestpublicvoidtestIf(){Assert.assertEquals("SUCCESS",mtDemo.testIf("0","1"));Assert.assertEquals("SUCCESS",mtDemo.testIf("1","0"));}还有一些复杂的情况,比如lambda,其实也需要覆盖不同的情况,返回不同的结果//源代码staticclassTestDto{privateStringname;私有字符串类型;TestDto(Stringname,Stringtype){this.name=name;this.type=类型;}publicStringgetName(){returnthis.name;}}publicListtestLambda(List列表){returnlist.stream().filter(l->l.getName().equals("name1")).collect(Collectors.toList());}//UT,只覆盖name1的存在,如果name1不存在则不覆盖覆盖@TestpublicvoidtestLambda(){Listlist=newArrayList<>();MTDemo.TestDtodto1=newMTDemo.TestDto("name1","type1");MTDemo.TestDtodto2=newMTDemo.TestDto("name2","type2");list.add(dto1);list.add(dto2);Assert.assertEquals("name1",mtDemo.testLambda(list).get(0).getName());}这个时候MT会强行修改lambda中的fiter部分,直接改成treu/false即可生成两个突变体。会有一个没有被覆盖,MT会标记SURVIVED//添加另一个UT来覆盖name1不存在的情况@TestpublicvoidtestLambda2(){Listlist=newArrayList<>();MTDemo.TestDtodto2=newMTDemo.TestDto("name2","type2");list.add(dto2);Assert.assertEquals(0,mtDemo.testLambda(list).size());}