测试工具说明
起始
很早就构思这么一个小工具, 但是在想用Java实现的时候,不知道如何能获取XMind中的内容,XMind好像没有提供Java解析的库。 直到有一天上网冲浪的时候发现XMind竟然能解压缩出JSON内容文件才开始做这个小工具。
基本描述
- 发布此文章前查了查各类技术社区与此相关的内容,有一些零散的用Python实现的,有一些把思路简单的讲了讲,还有与我思路相同的大佬, 看大佬的发布文章的时候还是2022年初,早看到大佬的文章自己就不用走弯路了。 但是没有看有整体技术实现过程。此文就是基于此,将整体的实现思路与实现过程描述出来,附上GitHub 项目,clone 下来之后可以立即运行使用。
- 环境 JDK11+ , 推荐使用JDK17以及以上版本
- 如果有人想在JDK8环境下运行此项目, 可以暂时将内容校验框架validation相关的代码删除(转CSV使用到了此校验)
测试工具实现思路
总体思路描述
我觉得一个标准的测试用例最基本的就是有三个元素用例标题、操作步骤和预期结果,别管是是功能的、性能的、接口的、白盒的,用例标题用以表示这个用例是做什么的,操作步骤和预期结果用以表示你要如何操作得出何种结果才算是证明此功能是通过你的测试。 再天马行空的自由发挥,如果一个用例缺少了这三种的任何一项都不能叫做测试用例最多算是需求描述/需求感悟/需求理解。
在日常工作中基本不可能一个XMind画布只描述一个用例,肯定要有一个用例所属的目录/项目, 所以XMind画布中一个分支中最好有四个节点,来对应此四个字段,否则就不应该叫测试用例,比如一些需求的理解、描述等。
使用XMind思维导图来写测试用例看中的就是自由性,所以在转文件的时候不能让编写者丧失了自由扩展节点的特性,如何保证编写者可以自由扩展节点,就只能从分支节点的最后往前找,当找到最后一个节点时,这个节点当做预期结果,那他的父节点就作为操作步骤, 此时用例标题不应该是操作步骤的父节点,而应该是这个分支之前的所有节点的连接。这样用以保证用例标题是独一无二的,事实上在一个项目中用例标题就应该是这样的,否则无法区分不同的用例要验证的功能。
到此为止就生成了以用例步骤为基准的一条测试用例,此方法用递归来实现是项目最核心的方法,用以提供基础数据。具体实现如下:
/**
* 进一步优化,获取步骤后先获取title再循环:
* @param xmind XMind 起始对象程序解析的数据源
* @param steps XMind 步骤集合,程序存储的结果
* @param builders 用于步骤间标题的传递
* @return 将XMind转为以步骤为基准的记录
* */
public List<XMindStep> convertToBaseAction(XMind xmind, List<XMindStep> steps, StringBuilder builders){
List<XMind> xmindList = xmind.getChildren().getAttached();
XMindStep step = new XMindStep();
builders.append(xmind.getTitle()).append("-");
StringBuilder sb = new StringBuilder();
for (XMind var: xmindList){
// 一直递归到当前节点没有子节为止
if (var.getChildren() != null){
convertToBaseAction(var, steps, builders);
}else {
// 预期结果赋值
sb.append(var.getTitle());
sb.append(System.getProperty("line.separator")); // 优化:预期结果换行
}
}
// 优化:减少不必要的代码, 解决同一层级下,较少节点的分支删除标题的问题
builders.replace(builders.length() - (xmind.getTitle().length() + 1), builders.length(),"");
if (!sb.toString().isEmpty()){
steps.add(step);
step.setStep(xmind.getTitle());
step.setExpectedResult(sb.toString().trim());
try {
step.setTitle(builders.substring(0, builders.length()-1));
}catch (Exception e){
throw new RuntimeException("请检查每条记录的层级是否足够,每条记录至少要保证三个节点");
}
}
return steps;
}
如果拿到最基础的数据后,在通过一系列的规则,修剪标题,判定优先级等优化得出一个个完整的测试单元。因为用例标题是父节点的连接,所以用例标题相同的步骤一定是同一个用例,就算他们看起来是完全不同的分支。
层级
层级是一种用例所在路径,用例属于哪个大模块下。当设置的层级超过XMInd画布能容纳的最大时就会报错,默认最顶层为0级, 比如:我的画布中节点有三个,层级却为一级,这就把操作步骤作为一个层级(路径)了,就会报错。所以推荐层级最低为0级时,在代码逻辑上节点最低为三个,个人推荐最少为四个(一个目录节点,三个标准测试用例节点),这样看起来比较好看。同时当前程序默认层级为二级,用以兼容最常见的场景。
预处理:解压
具体实现如下:
try {
ZipFile zipFile = new ZipFile(xmindFileSource);
Enumeration<?> entries = zipFile.entries();
while (entries.hasMoreElements()){
ZipEntry entry = (ZipEntry) entries.nextElement();
if (entry.getName().equals(sourceFileName)){
xmindJSONToString = IOUtils.toString(new BufferedInputStream(zipFile.getInputStream(entry)),"UTF-8");
}
}
} catch (IOException e) {
e.printStackTrace(System.out.append("解压出现问题请检查Xmind文件"));
}
转换策略
当前提供的转换策略有两种:CSV 和 EXCEL, 具体实现见:XMindExportStrategyEnum.class
Excel 转换策略
- 横向单元格设置策略
- 纵向单元格设置策略 CustomColumnCellStyleStrategy.class
- 列换设置策略 CustomColumnWidthStyleStrategy.class
- 单元格合并策略 ExcelMergeStrategy.class
横向、纵向单元格样式设置主要设置一般单元格样式。
列换设置策略根据单元格内容调整列宽长度,用以适应各种XMind转换结果
单个格合并策略用来实现将相同的用例不中合并到一块,形成一个用例
具体实现较长见github源码,其中应该有一些冗余代码,后续版本调整。
CSV 转换
CSV就是生成标准的用例字符串后直接写入到文件中
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。