今天,我们将介绍一个工具Squaretest,它是一个用于自动生成单元测试的插件。它也将被使用,因为该公司最近实施了代码质量控制指标,以评估各种项目的单元测试覆盖率和声纳扫描的各种问题。
许多旧项目和旧代码,或者需要匆忙交付的项目,都严重缺少单元测试,覆盖率不到5%。所以最近几天,几个小伙伴一直在疯狂地堆积单元测试。三个人把两天的单元测试累积到30%。所以我也来帮忙写了两篇。当我写第二篇时,我发现这项工作不应该由人来做。我们应该查看原始代码,然后根据逻辑编写各种模拟,我觉得有一些东西可以遵循,所以我检查了一下,发现有插件可以帮助我们做到这一点。然后我看了一眼。
我使用这个想法。首先,让我们下载插件。文件-->设置-->插件,搜索Squaretest,然后安装它。安装插件后,需要重新启动它
重新启动后,菜单栏会有一个额外的方形测试。让我们来讨论一下如何使用它。通过查看菜单的最后一项:生成测试方法(帮助),您也可以看到它的演示,但演示尚未完成。我将在下面截图,向您展示如何使用它和一些经验。
首先,我们开一个类,这是我们要测试的类。这个类有七个公共方法,因为Squaretest生成的单元测试方法只能生成public。当然,这是合理的!毕竟,私人电话必须由公众拨打。
如果我们要手工编写这个类的单元测试,那么需要一段时间来研究它。现在让我们来看看我的操作。打开类,将光标放在代码中,然后右键单击鼠标以选择Generate…
然后您将看到两个熟悉的图标。第一次选择第二个选项时,它将允许您为单元测试选择模板。因为我已经选择了它,所以我不会再次弹出演示,但稍后我会告诉您如何更改模板。
选择第二项后,将弹出一个框。在这里,它将自动识别需要Mock的当前类的成员变量。直接单击“确定”
将使用类的真实目录层次结构在测试文件夹中自动创建单元测试类。类名是原始类名,后跟Test
我会把代码发给你,看看它生成了什么。让我们看看它是否可怕、可怕、可怕。七种单元测试方法将在几秒钟内发布。你要写多长时间?毕竟,时间就是金钱!那我们试试吧!
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 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 crawlerScreenShotTaskDtos = Arrays.asList(crawlerScreenShotTaskDto);
when(mockCrawerScreenShotTaskMapper.listJobScreenShotTask(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskDtos);
// Run the test
final List 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 pimScreenShotVos = Arrays.asList(pimScreenShotVo);
when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);
// Run the test
final PageInfo 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 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 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 crawlerScreenShotTaskSyncDtos = Arrays.asList(crawlerScreenShotTaskSyncDto1);
when(mockCrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskSyncDtos);
// Run the test
final List 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菜单中按倒数第一个。按下快捷键的效果如下。我选择了这个模板,您也可以使用它作为参考。
好了,上面的SQUARETEST部分结束了。当然,拉动并不为时过早。这个类是一个比较成功的案例,您仍然需要做一些小的修改。毕竟,它生成的测试数据可能与if-else数据不匹配,对吗?但这很容易改变。这从if else的自我分析变为调试,查看生成的数据是否有问题。更改数据将被传递。无论如何,我对它很满意,我可以适当地节省70%的工作量。
解决了上述问题后,发现了另一个问题。对于VO、DTO、entity、Command和Model等实体类,我们通常使用lombok注释,如get、set和约束构造函数。但是,该工具只能为这些实体类的构造函数生成单元测试,而不能为get set方法生成单元测试。因此,我们编写一个由实体类继承的基方法,只需编写两行磁带。请参见以下代码:
@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public abstract class BaseVoEntityTest {
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在实体类上生成单元测试,然后继承我上面写的基类。vo的单元测试代码略有更改,如下所示
观看运行后,覆盖率为100%,这是合适的。通过这两种解决方案,我们可以在一天内实现60%以上的覆盖率。不要太激动。你可以尝试一下。当然,这不是一个专门为跑腿而编写的单元测试。我们还可以使用这个工具在后续开发中生成和测试我们自己的代码,这也提高了我们的工作效率!