数据驱动测试,减少重复代码
参数化测试
最近在参加一个架构解耦的项目,在里面开发了多个工具,因为工具是构建过程中所有服务都会使用,所以对质量要求比较高。做事前,三思而后行,为了未来这个工具质量不至于恶化的比较严重,我准备交付这个工具前,一定要把工具用例写好。为后面承接该工具的兄弟做地实在的建设。
因为是针对工具进行测试,工具类似一个函数一样,每个测试用例都需要定义输入和输出,用例整理完成后,发现:如果一个用例一个用例地写,手会写断,而且存在大量的冗余代码,难以维护,网上寻思半天,发现“参数化测试”可以解决我的问题。
废话不多说,言归正传。
参数化测试,侠义来讲,是指将定义测试过程,通过输入不同参数,得到具体的不同用例;广义来讲,是指的一种数据驱动测试的设计思想。总之,解决的是软件中基本的冗余问题,是通过将测试架构分层,将测试因子组合抽象为测试数据,将测试过程抽象为测试行为,最后将数据和行为叠加在一起,形成丰富全面的测试用例。
参数化测试可以为整个软件测试,带来如下好处:
- 测试代码更简洁,更易维护。显而易见,测试代码沉淀的是公共的测试过程,不会包含其他冗余的数据代码。
- 用例开发更高效。通过新增数据,即可快速增加新的用例。
当然,按辩证的唯物主义思想来看,任何事物都有两面性,参数化测试,实际也存在一些“坏处”:
- 参数化测试,使得测试软件架构分层,本身复杂度增加,数据与行为的边界存在约定的关联关系。
- 对用例开发质量要求更高。整个项目开发过程中,我修改了多次测试行为实现,多次引发大批量的测试用例失败,😓
- 扩展性有限,数据、行为分离的测试架构,也给整个测试定义了各种规则,所有用例必须在既定的规则世界中存活,打破规则的用例,无法寄生在这个“世界“中。
以上都比较虚,纯理论,马克思主义告诉我们,实践是检验真理的唯一标准。我们来点实在的。
因为是针对于工具进行测试,工具大体作用是输入一些文件和参数,输出新的文件。参考linux文件系统架构,我将所有测试中设计的参数,都文件化,按目录组织每个用例。
工具使用方法:
Usage: modelfriend [--dsttype=<dstType>] --model=<modelName> -s=<originFile>
--scene=<sceneName> -t=<targetFile>
make new models from origin models on specified scense.
--dsttype=<dstType> Output the new model file with specified file type,
Values:xml, json, ini, properties, macro_ini
--model=<modelName> The model driver which is used to read or write
file.
-s, --source=<originFile> The origin file which is used to make new models
file.
--scene=<sceneName> The directory which has stored with the scene cfg
files.
-t, --target=<targetFile> The new model file.
通用测试过程:
#!/bin/sh
pwd;
pushd $1;
# 输入参数,通过工具处理原始文件,得到新的文件
java -jar $2 -s $3 -t $4 --model=$5 --scene=$6;
# 检查新的文件,是否与期望的文件是一致
diff $7 $8;
[ $? -eq 0 ] || exit 1;
popd;
测试数据设计:
- 每一个目录都是一个测试用例。
- 目录名称按固定格式组织,携带了对应的model参数,便于用例设计和管理
- 目录下,文件命名按照固定规则命名(src…,dst…)src…表示文件作为工具的源文件,dst…表示文件作为工具输出的目标文件,edge作为工具的参数配置
最终,通过如下代码,定义测试过程:
public class ModelToolTestSuite {
private static final String[] fileters = {}; //"_mml.model_"
private static boolean isMatch(String name) {
if(fileters.length == 0) {
return true;
}
return Arrays.asList(fileters).stream().anyMatch(name::contains);
}
@Parameterized.Parameters(name = "{index} : {0}")
public static Collection<Object[]> data() {
List<Object[]> parameters = new ArrayList<>();
try {
File root = new File(ModelToolTestSuite.class.getClassLoader().getResource(".").toURI());
for( File dir : root.listFiles()) {
if(dir.isDirectory() && dir.getName().contains("case_") && isMatch(dir.getName())) {
String[] pars = {dir.getName()};
parameters.add(pars);
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
return parameters;
}
@Parameterized.Parameter(0)
public String caseName;
@Test
public void RunTest()
{
ModelToolTestBean d = ModelToolTestHelper.MakeTestCaseData(caseName);
Assert.assertNotNull(d);
Boolean isOk = ModelToolTestHelper.RunWithData(d);
Assert.assertTrue(isOk);
}
}
整个测试结果如下:
(完结)
- 点赞
- 收藏
- 关注作者
评论(0)