自动化测试常用的数据驱动方式

在日常的测试工作中,从理论上来说,一个接口方法可以用一个用例就搞定测试,然后传入不同的参数的不同组合,在用例方法里做不同的分支判断校验。看似很美好,包罗万象的参数组合,实现其来很麻烦,且有如下缺点:
  1. 且需要花大量的精力去判断分支路径,并做不同的断言,破坏了方法的原子性,不要指望一个方法干所有事情,我们一直强调模块化编程。
  2. 脚本存在大量的if-else分支,for循环等,脚本可读性差 维护成本高。
  3. 测试没有侧重点。
那么,有什么好的方法来避免这个问题呢?首先,我们要明白为什么要做数据驱动,数据驱动的原则是什么?这个问题,相同字段,输入不同的数据,通过调取被测代码,获取不同的测试结果。每组数据都是相同的字段,进一步可以把一组参数抽象为一个对象,这一组参数组合就是这个对象的不同元素。我们要做的工作就是不断创建这样的对象,并传递给测试方法。那么数据驱动怎么做呢?有哪些数据驱动方式呢?一般来说,主要有以下几种方式传入数据:
  1. 以硬编码的方式写在代码里,简单直观,但代码和数据未分离,不方便以后维护。
  2. 从文件读取数据,如csv,excel、txt、xml等格式文件。不用修改测试逻辑,只需要维护测试数据。
  3. 直接调用接口获取数据源。
  4. 本地封装一些生成数据的方法。
以上几种方式生成的数据,在@DataProvider方法中以Object二位数组返回数据,测试用例可以直接获取。通过@datapovider方法数据驱动有以下几点优点:
1.像在循环里一样,自动遍历所有数据组合
2.某一组数据执行测试方法失败,不会影响其他数据组合继续执行。
3.测试代码不用加过多的数据判断,要的只是对被测代码的数据输出和结果断言。
例如要测试一个列表查询的接口,有很多查询条件,那么需要测试,默认查询、单一条件查询、组合条件查询等场景,其实就是设置不同的查询参数,其余测试步骤及校验大抵相同。
1.单一条件查询,遍历所有查询条件,传入测试方法,数据的获取需要封装成合适的方法,可读性好,例如这里buildQueryParmGroup方法就是封装构造查询参数的方法
private static Map<String, String> buildQueryParmGroup() {
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("id", "1003266");
    map.put("type", "1");
    map.put("venderId", "20032");
    map.put("businessId", "100073920");
    map.put("title", "砍价活动api测试");
    map.put("skuId", "1200039810");
    map.put("oneCategory", "1315");
    map.put("twoCategory", "1342");
    map.put("threeCategory", "9733");
    map.put("beginTime", "2017-01-04 16:19:45");
    map.put("endTime", "2017-02-03 16:19:45");
    map.put("status", "1");
    map.put("pin", "test_sop01");
    map.put("customerPin", "sop_order_new");
    return map;
}

  @DataProvider(name = "queryParamProperties")
    public static Object[][] queryParamProperties() {
        Map<String, String> queryParmGroup = buildQueryParmGroup();
        Set<Map.Entry<String, String>> entrySet = queryParmGroup.entrySet();
        Object[][] objects = new Object[entrySet.size()][];
        Object[] objects1 = entrySet.toArray();
        for (int i = 0; i < objects.length; i++) {
            objects[i] = new Object[]{objects1[i]};
        }

        return objects;
    }

    @Test(dataProvider = "queryParamProperties")
    @Description(description = "单一条件查询砍价列表")
    public void testGetByBargainList_2(Map.Entry<String, String> entry) throws Exception {
//        ConvertUtils.register(new DateLocaleConverter(), Date.class);
        ConvertUtils.register(new Converter() {
            public Object convert(Class type, Object value) {
                if (value == null) {
                    return null;
                }
                if (!(value instanceof String)) {
                    throw new ConversionException("传入的不是字符串");
                }
                if (((String) value).trim().equals("")) {
                    return null;
                }
                DateFormat df = new SimpleDateFormat(PromoConstant.YYYYMMDDHHMMSS);
                try {
                    return df.parse((String) value);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }

            }
        }, Date.class);
        BargainQueryParm queryParam = new BargainQueryParm();
        BeanUtils.setProperty(queryParam, entry.getKey(), entry.getValue());

        Result<List> bargainList = this.invoke(bargainReadService, "getBargainList", List.class, clientInfo, queryParam);
        Assert.assertTrue(bargainList.isSuccess());
    }
组合条件查询,随机生成参数组合,查询条件放到一个map里,封装一个buildQueryParmSubMap方法用于随机生成查询条件组合,返回一个map<条件参数名,条件参数值>
private static Map<String, String> buildQueryParmSubMap(Map<String, String> map, int size) {
    Set<Map.Entry<String, String>> entries = map.entrySet();

    ImmutableSet<Map.Entry<String, String>> subSet = ImmutableSet.copyOf(Iterables.limit(entries, size));
    Map<String, String> subMap = new HashMap<String, String>();
    Iterator<Map.Entry<String, String>> iterator = subSet.iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> entry = iterator.next();
        subMap.put(entry.getKey(), entry.getValue());
    }

    return subMap;
}
数据驱动方法:
@DataProvider(name = "queryParmGroup")
public static Object[][] queryParmGroup() {
    Map<String, String> queryParmGroup = buildQueryParmGroup();
    Object[][] objects = new Object[100][];
    for (int i = 0; i < objects.length; i++) {
        objects[i] = new Object[]{buildQueryParmSubMap(queryParmGroup, RandomUtils.nextInt(queryParmGroup.size()))};

    }

    return objects;

}
@Test(dataProvider = "queryParmGroup")
@Description(description = "组合条件查询砍价列表")
public void testGetByBargainList_3(Map<String, String> map) throws Exception {
    ConvertUtils.register(new Converter() {
        public Object convert(Class type, Object value) {
            if (value == null) {
                return null;
            }
            if (!(value instanceof String)) {
                throw new ConversionException("传入的不是字符串");
            }
            if (((String) value).trim().equals("")) {
                return null;
            }
            DateFormat df = new SimpleDateFormat(PromoConstant.YYYYMMDDHHMMSS);
            try {
                return df.parse((String) value);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
    }, Date.class);
    BargainQueryParm queryParam = new BargainQueryParm();
    BeanUtils.populate(queryParam, map);

    Result<List> getBargainList = this.invoke(bargainReadService, "getBargainList", List.class, clientInfo, queryParam);
    Assert.assertTrue(getBargainList.isSuccess());
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值