原创:testng 参数化(4)- 使用注解获取csv文件

简介

前篇提到,使用@DataProvider读取csv中的数据文件,来逐行执行测试用例。已经很好的实现了数据和逻辑的完全隔离,
并且代码结构也是相当清晰明了。再进一步,使用java注解方式来引入csv文件,则会使得文件结构更加简洁
使用注解来引入csv文件,从而逐行执行测试用例

java注解简单介绍

java注解一种标记式高耦合的配置方式。注解可以配置在方法上,类上,字段属性上,几乎需要配置的地方都可以进行注解。

注解的本质

java.lang.annotation.Annotation 接口中是这样来描述
The common interface extended by all annotation types, 意思是所有注解都继承了Annotation接口

举一个例子,Override注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {

}

实际上就是:

public interface Override extends Annotation{
   
}

所以,注解的本质就是一个继承了 Annotation 接口的接口
可以把注解理解为一种特殊的注释,这种注释可以用代码来解析。

元注解

修饰注解的注解为元注解,用在注解的定义上

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {

}

JAVA 中有以下几个『元注解』:

  • @Target:
  • @Retention:
  • @Documented
  • @Inherited:

@Target 用于指明注解的作用目标
作用目标是一个枚举类型,有以下一些值:

  • ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
  • ElementType.FIELD:允许作用在属性字段上
  • ElementType.METHOD:允许作用在方法上
  • ElementType.PARAMETER:允许作用在方法参数上
  • ElementType.CONSTRUCTOR:允许作用在构造器上
  • ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
  • ElementType.ANNOTATION_TYPE:允许作用在注解上
  • ElementType.PACKAGE:允许作用在包上

@Retention:用于指明注解的生命周期

  • RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
  • RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
  • RetentionPolicy.RUNTIME:永久保存,可以反射获取

自定义注解

自定义注解中包含文件名称

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamFile {
    public String fileName() default "";
}

读取注解中的数据

第一步,获取到注解中fileName文件名称
构造一个监听器,每次执行DataProvider之前,读取测试方法中的注解上的文件名称

@Listeners
public class DataProviderListenerImp implements IDataProviderListener {
    @Override
    public void beforeDataProviderExecution(IDataProviderMethod dataProviderMethod, ITestNGMethod testNGMethod, ITestContext context){
        Method[] methods = testNGMethod.getRealClass().getDeclaredMethods();
        if(methods!=null){
            for(Method method:methods){
                if(method.getName().equals(testNGMethod.getMethodName())){
                    ParamFile paramFile = method.getAnnotation(ParamFile.class);
                    ParamDataProvider.fileName =  paramFile.fileName();
                }
            }
        }
        System.out.println("beforeDataProviderExecution finished");
    }

    @Override
    public void afterDataProviderExecution(IDataProviderMethod dataProviderMethod, ITestNGMethod testNGMethod, ITestContext context){
        ParamDataProvider.fileName = "";
    }
}

第二步,获取到文件名称后,读取文件中的测试数据

import common.util.csvutils.CSVUtils;
import org.testng.annotations.DataProvider;
import java.util.Map;

public class ParamDataProvider {
    public static String fileName = "";
    @DataProvider(name = "annoCsvData")
    public Object[][] readCsvData(){
        //读入csv文件数据并转化为Object[][]
        Map<Integer, Map<String,Object>> map = CSVUtils.readFile(fileName);
        Object[][] objects = new Object[map.size()][1];
        for(int i=0; i<map.size(); i++){
            Object[] temp = new Object[1];
            temp[0] = map.get(i+1);
            objects[i][0]=temp;
        }
        return objects;
    }
}

使用@DataProvider中的监听器

本例子中,使用了testNG中的监听器,关于监听器,参考 监听器 一章

运行结果

beforeDataProviderExecution finished
{age=1, city=BJ, code=0, data=good cat, describe=冒烟测试, id=1, msg=success, name=tom}
success
{age=100, city=TOKYO, code=1, data=, describe=异常测试, id=2, msg=doesn't exist, name=jerry}
doesn't exist
beforeDataProviderExecution finished
{age=1, city=BJ, code=0, data=good cat, describe=冒烟测试, id=1, msg=success, name=tom}
tom
{age=100, city=TOKYO, code=1, data=, describe=异常测试, id=2, msg=doesn't exist, name=jerry}
jerry

===============================================
liang6Demo
Total tests run: 4, Failures: 0, Skips: 0
===============================================
版权所有,本文为原创文章,转载请注明出处
https://www.cnblogs.com/liang6/p/14395828.html

总结

使用注解后的测试用例,看起来如下:

class Liang6DemoAnnoCsv {

    @Test(dataProvider = "annoCsvData", dataProviderClass= ParamDataProvider.class)
    @ParamFile(fileName = "liang6demo.csv")
    public void annoCsvData(Object[] obj){
        Map<String, Object> mapLine = (Map<String, Object>)obj[0];
        System.out.println(obj[0]);
        System.out.println(mapLine.get("msg"));
    }

    @Test(dataProvider = "annoCsvData", dataProviderClass= ParamDataProvider.class)
    @ParamFile(fileName = "liang6demo.csv")
    public void annoCsvData2(Object[] obj){
        Map<String, Object> mapLine = (Map<String, Object>)obj[0];
        System.out.println(obj[0]);
        System.out.println(mapLine.get("name"));
    }
}

只需要在@ParamFile中配置csv文件名称即可,代码看起来,整洁度和结构性更加清晰简明

posted @ 2021-02-13 13:42  嘉良空间  阅读(348)  评论(0)    收藏  举报