明天来介绍一款工具 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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!