添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

不点 ,我们哪来故事?

一个指导程序员进入大公司/独角兽 ‍ 的精品社群,致力于分享职场达人的专业打法,包括「学习路线+简历模板+实习避坑+笔试面试+试用转正+升职加薪+跳槽技巧」。

点这里去了解,剑指大厂吧!

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

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

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

我使用的是idea,我们先来下载一下插件, File——>Settings——>Plugins ,搜索 Squaretest ,然后 install 就好了,插件安装完成后需要重启一下

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

首先我们打开一个类,这个类就是我们即将要作为实验的类,这个类有7个public方法,因为 Squaretest 生成的单元测试方法都是只能生成public的,当然这也是合理的嘛!毕竟private的肯定被public调用了。

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

然后你就会看到这里有两个熟悉的图标,第一次的话选择第二个选项,它会让你选择你一下单元测试的模板,因为我已经选择过了,所以我现在演示不回再弹出,但后面我会告诉你怎么更改模板。

自动会使用类的真实目录层次在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 ;

PropertyDeor pd = new PropertyDeor(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%以上,不要太刺激,大家可以用用试试哦,当然这个也不是纯为了应付差事写的单元测试,我们后续开发的时候,也可以用这个工具来生成,然后自测自己的代码,这样也是提升工作效率的嘛!

欢迎加入我的知识星球,一起剑指大厂,不断晋升 加薪。

剑指大厂不仅是一个获取信息的圈子,还是一个规划职业的导师。已在知识星球,更新如下 点这里去了解,剑指大厂吧! ( 或点击下图了解 ):

////// END //////

↓ 点击下方关注,看更多架构分享 ↓ 返回搜狐,查看更多

责任编辑:

平台声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。