明天来介绍一款工具Squaretest,它是一款主动生成单元测试的插件,为什么会用到它?

次要因为最近公司上了代码品质管控的指标,会考评各个我的项目的单元测试覆盖率,以及sonar扫描进去的各种问题,很多老我的项目老代码,或者焦急交付的我的项目,单元测试重大缺失,覆盖率只有5%不到。

所以几个小伙伴这几天就在疯狂的堆单元测试,3集体堆了2蠢才堆到30%,于是我也来上手帮忙写了两个,写到第二个的时候就发现,这个活不应该是人干的,要去看原来的代码,而后依据逻辑写各种Mock,感觉是有迹可循的货色,所以就查了下,发现果然有插件帮咱们来干这个事件,那么解下来就来看看。

另外,更多 IDEA 好用的插件全副整顿好了,微信搜寻Java技术栈,在后盾发送:工具,能够在线浏览。

我应用的是idea,咱们先来下载一下插件,File——>Settings——>Plugins,搜寻Squaretest,而后install就好了,插件装置实现后须要重启一下

重启之后,菜单栏就多了一项Squaretest,上面咱们来讲下怎么用,大家也能够通过看这个菜单的最初一项:Generate Test Methods(Help)来看它的一个演示,但演示不太全,我上面截图给大家看下我怎么用的,以及一些应用心得。

首先咱们关上一个类,这个类就是咱们行将要作为试验的类,这个类有7个public办法,因为Squaretest生成的单元测试办法都是只能生成public的,当然这也是正当的嘛!毕竟private的必定被public调用了。

如果咱们来手写这个类的单元测试,光看都要一会,上面看我操作,关上你的类,光标定位到代码里,右击鼠标抉择Generate…

而后你就会看到这里有两个相熟的图标,第一次的话抉择第二个选项,它会让你抉择你一下单元测试的模板,因为我曾经抉择过了,所以我当初演示不回再弹出,但前面我会通知你怎么更改模板。

抉择第二项后就会弹出一个框看上面这里它主动会辨认出以后类须要Mock的成员变量,间接点ok

主动会应用类的实在目录档次在test文件夹中创立进去一个单元测试类,类名就是原类名后加Test

我把代码贴出来给大家看看它生成进去的是什么样的,看看吓不吓人,牛逼牛逼,7个单元测试办法,秒秒钟就进去了,各位看官你们本人写要多久能写进去,毕竟工夫就是金钱啊!而后咱们执行一把试试!

public class CrawlerScreenShotServiceImplTest {    @Mock    private CrawerScreenShotTaskMapper mockCrawerScreenShotTaskMapper;    @Mock    private CrawerScreenShotTaskLogMapper mockCrawerScreenShotTaskLogMapper;    @InjectMocks    private CrawlerScreenShotServiceImpl crawlerScreenShotServiceImplUnderTest;    @Before    public void setUp() {        initMocks(this);    }    @Test    public void testReceiveData() {        // Setup        final CrawlerScreenShotVO vo = new CrawlerScreenShotVO();        vo.setUrl("url");        vo.setPcFlag(false);        vo.setMembergroup("membergroup");        vo.setTaskType(0);        vo.setUrlType(0);        when(mockCrawerScreenShotTaskLogMapper.saveSelective(any(CrawerScreenShotTaskLog.class))).thenReturn(0);        when(mockCrawerScreenShotTaskMapper.saveBatch(Arrays.asList(new CrawlerScreenShotTask(0L, "url", "imageOssUrl", false, false, "memberGroup", 0, 0, "fileName", new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), false, "skuCode", "state", "operater")))).thenReturn(0);        // Run the test        final Result<String> result = crawlerScreenShotServiceImplUnderTest.receiveData(vo);        // Verify the results    }    @Test    public void testListJobScreenShotTask() {        // Setup        // Configure CrawerScreenShotTaskMapper.listJobScreenShotTask(...).        final CrawlerScreenShotTaskDto crawlerScreenShotTaskDto = new CrawlerScreenShotTaskDto();        crawlerScreenShotTaskDto.setId(0L);        crawlerScreenShotTaskDto.setUrl("url");        crawlerScreenShotTaskDto.setSkuCode("skuCode");        crawlerScreenShotTaskDto.setPcFlag(false);        crawlerScreenShotTaskDto.setMemberGroup("memberGroup");        crawlerScreenShotTaskDto.setUrlType(0);        crawlerScreenShotTaskDto.setFileName("fileName");        crawlerScreenShotTaskDto.setTaskType(0);        crawlerScreenShotTaskDto.setState("state");        final List<CrawlerScreenShotTaskDto> crawlerScreenShotTaskDtos = Arrays.asList(crawlerScreenShotTaskDto);        when(mockCrawerScreenShotTaskMapper.listJobScreenShotTask(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskDtos);        // Run the test        final List<CrawlerScreenShotTaskDto> result = crawlerScreenShotServiceImplUnderTest.listJobScreenShotTask();        // Verify the results    }    @Test    public void testQuery() {        // Setup        final NikeScreenShotListRequestVo requestVo = new NikeScreenShotListRequestVo();        requestVo.setUrl("url");        requestVo.setUrlType(0);        requestVo.setStartTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        requestVo.setEndTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        requestVo.setStatus(0);        requestVo.setPcFlag(0);        requestVo.setPageNum(0);        requestVo.setPageSize(0);        // Configure CrawerScreenShotTaskMapper.query(...).        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();        pimScreenShotVo.setId(0L);        pimScreenShotVo.setUrl("url");        pimScreenShotVo.setImageOssUrl("imageOssUrl");        pimScreenShotVo.setStatus(0);        pimScreenShotVo.setPcFlag(false);        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        pimScreenShotVo.setUrlType(0);        pimScreenShotVo.setMsg("msg");        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);        // Run the test        final PageInfo<PimScreenShotVo> result = crawlerScreenShotServiceImplUnderTest.query(requestVo);        // Verify the results    }    @Test    public void testQuerySelectBoxData() {        // Setup        // Configure CrawerScreenShotTaskMapper.query(...).        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();        pimScreenShotVo.setId(0L);        pimScreenShotVo.setUrl("url");        pimScreenShotVo.setImageOssUrl("imageOssUrl");        pimScreenShotVo.setStatus(0);        pimScreenShotVo.setPcFlag(false);        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        pimScreenShotVo.setUrlType(0);        pimScreenShotVo.setMsg("msg");        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);        // Run the test        final PimScreenShotTaskParamsDto result = crawlerScreenShotServiceImplUnderTest.querySelectBoxData();        // Verify the results    }    @Test    public void testFindExecutionScreenShotTaskCount() {        // Setup        when(mockCrawerScreenShotTaskMapper.findExecutionScreenShotTaskCount()).thenReturn(0);        // Run the test        final Integer result = crawlerScreenShotServiceImplUnderTest.findExecutionScreenShotTaskCount();        // Verify the results        assertEquals(0, result);    }    @Test    public void testFindCrawerScreenshotTaskByCreateTime() {        // Setup        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto = new CrawlerScreenShotTaskSyncDto();        crawlerScreenShotTaskSyncDto.setId(0L);        crawlerScreenShotTaskSyncDto.setUrl("url");        crawlerScreenShotTaskSyncDto.setSkuCode("skuCode");        crawlerScreenShotTaskSyncDto.setTaskType(0);        crawlerScreenShotTaskSyncDto.setStatus(0);        crawlerScreenShotTaskSyncDto.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        crawlerScreenShotTaskSyncDto.setOperater("operater");        crawlerScreenShotTaskSyncDto.setMsg("msg");        final List<CrawlerScreenShotTaskSyncDto> expectedResult = Arrays.asList(crawlerScreenShotTaskSyncDto);        // Configure CrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(...).        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto1 = new CrawlerScreenShotTaskSyncDto();        crawlerScreenShotTaskSyncDto1.setId(0L);        crawlerScreenShotTaskSyncDto1.setUrl("url");        crawlerScreenShotTaskSyncDto1.setSkuCode("skuCode");        crawlerScreenShotTaskSyncDto1.setTaskType(0);        crawlerScreenShotTaskSyncDto1.setStatus(0);        crawlerScreenShotTaskSyncDto1.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        crawlerScreenShotTaskSyncDto1.setOperater("operater");        crawlerScreenShotTaskSyncDto1.setMsg("msg");        final List<CrawlerScreenShotTaskSyncDto> crawlerScreenShotTaskSyncDtos = Arrays.asList(crawlerScreenShotTaskSyncDto1);        when(mockCrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskSyncDtos);        // Run the test        final List<CrawlerScreenShotTaskSyncDto> result = crawlerScreenShotServiceImplUnderTest.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        // Verify the results        assertEquals(expectedResult, result);    }    @Test    public void testQueryCrawlerDashboard() {        // Setup        when(mockCrawerScreenShotTaskMapper.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(0);        // Run the test        final Integer result = crawlerScreenShotServiceImplUnderTest.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());        // Verify the results        assertEquals(0, result);    }}

报错了呢,不要慌,这个断言是为了查看你单元测试跑进去的后果是否合乎预期的,如果你不想查看只想实现覆盖率,间接干掉就能够了(手动狗头)。

怎么样!刺不刺激,爽不爽,秒秒钟90多行的代码覆盖率就到了90%以上.

下面说过第一次进来会让你抉择单元测试的模板,如果你要切换的话能够在单元测试类中按快捷键,Alt+M,或者通过Squaretest的菜单倒数第二个,上面这个就是按快捷键的成果,我抉择的是这个模板,你们也能够借鉴。

OK,以上Squaretest局部就完结了,当然拉也不能快乐的太早,这个类算是比拟胜利的状况,很多时候还是要你本人小修小改的,毕竟它生成进去的测试数据可能齐全匹配不上你的if else数据对吧,但这都很好改啊,这样就从本人剖析if else变成了,debug程序了呀,哪里报错,debug过来,看看是不是生成的数据有问题,改个数据,就通过了,反正自己用的是很舒畅的,妥妥的节俭70%的工作量。

解决了下面一个问题之后,又发现另一个问题,这个工具VO,DTO,Entity,Command,Model这种实体类来讲,个别这种实体类咱们都用lombok的注解get,set,还有constract结构器等注解,然而这个工具只能生成这些实体类的结构器的单元测试,无奈生成get set办法的单元测试,所以写了个base办法,实体类继承一下,简略的写两行带就好了,看上面代码:

@SpringBootTest@RunWith(MockitoJUnitRunner.class)public abstract class BaseVoEntityTest<T> {    protected abstract T getT();    private void testGetAndSet() throws IllegalAccessException, InstantiationException, IntrospectionException,            InvocationTargetException {        T t = getT();        Class modelClass = t.getClass();        Object obj = modelClass.newInstance();        Field[] fields = modelClass.getDeclaredFields();        for (Field f : fields) {            boolean isStatic = Modifier.isStatic(f.getModifiers());            // 过滤字段            if (f.getName().equals("isSerialVersionUID") || f.getName().equals("serialVersionUID") || isStatic || f.getGenericType().toString().equals("boolean")                    || f.isSynthetic()) {                continue;            }            PropertyDescriptor pd = new PropertyDescriptor(f.getName(), modelClass);            Method get = pd.getReadMethod();            Method set = pd.getWriteMethod();            set.invoke(obj, get.invoke(obj));        }    }    @Test    public void getAndSetTest() throws InvocationTargetException, IntrospectionException,            InstantiationException, IllegalAccessException {        this.testGetAndSet();    }}

同样的形式咱们在实体类上通过Squaretest生成单元测试,而后继承我下面写的那个base类,vo的单元测试代码稍加改变,如下

看run完之后,覆盖率100%,妥妥的,通过这两个解决方案,一天之内咱们就把覆盖率搞到了60%以上,不要太刺激,大家能够用用试试哦,当然这个也不是纯为了应酬差事写的单元测试,咱们后续开发的时候,也能够用这个工具来生成,而后自测本人的代码,这样也是晋升工作效率的嘛!

感觉不错就用起来吧!

版权申明:本文为CSDN博主「孙琛斌(浮生)」的原创文章,遵循CC 4.0 BY-SA版权协定,转载请附上原文出处链接及本申明。原文链接:https://blog.csdn.net/sun5769...

近期热文举荐:

1.1,000+ 道 Java面试题及答案整顿(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!