背景TestNG 监听器 — IAnnotationTransformer2代码实现实现 transform()效果展示
背景很多测试框架都带有数据驱动的方式,如TestNG 的 @DataProvider ,在合理使用下可以大大减少代码量,同时也便于后期维护。而熟悉TestNG的同学应该都知道,使用TestNG 的 @DataProvider 时需要先写一个数据源,再 @Test(dataProvider=“xx”) 中引用数据源。 而慢慢看到有不少用例用的数据源,QA是写在Excel等文件里面,这时就觉得直接用原生的略微麻烦了,为啥不能把数据源直接与注解的方式写在测试用例上呢?如下:
@OTPDataProvider(dataFile = "src/test/resources/excel/demo1.xlsx",sheetName = "sheet1") @Test public void excelData(JSONObject jsonObject) { log.info(jsonObject.toJSONString()); }
TestNG 监听器 — IAnnotationTransformer2为了实现上面的效果,查阅TestNG官方文档,发现有个 IAnnotationTransformer2 接口, IAnnotationTransformer2 接口继承了 IAnnotationTransformer,而IAnnotationTransformer 接口提供了 public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) 方法,从方法说明上看这个接口可以在@Test用例被调用前操作相应的注解。基于这个监听器的能力,那就自然会想到,如果在 @Test 用例执行时,动态的生成@DataProvider ,并 @Test上动态添加 dataProvider属性不就可以。
代码实现
实现 transform()核心代码其实就2行:// 动态设定 dataProvider = “xxxx”annotation.setDataProvider(OTPDataProvider.NAME);// 动态设定 @DataProvider 的classannotation.setDataProviderClass(ExcelDataProvider.class);
/** * 从 IAnnotationTransformer 接口继承 操作 @Test * * @param annotation * @param testClass * @param testConstructor * @param testMethod */ @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { boolean annotationDataProvider = testMethod.isAnnotationPresent(OTPDataProvider.class); if (annotationDataProvider) { annotation.setDataProvider(OTPDataProvider.NAME); DataProviderUtil.chooseData(annotation, testMethod); }// 重跑 IRetryAnalyzer retry = annotation.getRetryAnalyzer(); if (retry == null) { annotation.setRetryAnalyzer(TestNGRetry.class); } } public void chooseData(ITestAnnotation annotation, Method method) { OTPDataProvider otpDataProvider = method.getAnnotation(OTPDataProvider.class); String file = otpDataProvider.dataFile().toLowerCase(); if (file.endsWith(JSON_TYPE)) { annotation.setDataProviderClass(JsonDataProvicer.class); } else if (!"".equals(otpDataProvider.sqlQuery())) { annotation.setDataProviderClass(SqlDataProvider.class); } else if (file.endsWith(TEXT_TYPE)) { annotation.setDataProviderClass(TxtDataProvider.class); } else if (file.endsWith(SUPER_EXCEL_TYPE) || file.endsWith(EXCEL_TYPE)) {// excel annotation.setDataProviderClass(ExcelDataProvider.class); }else { log.error("OTPDataProvider 属性值有误 请认真检查!"); } }
@DataProvider(name = OTPDataProvider.NAME) public Iterator
效果展示