给测试小姐姐优化代码——干掉if-else

2018-11-01  本文已影响0人  Vongola々骸

友情提示,这篇的代码比较多,可以选择性阅读


最近测试小姐姐在写自动化测试case,之前我就和测试小姐姐提过,她写的代码确实有点臃肿,可以考虑优化一下,减少冗余代码,提高可读性和可维护性......
估计小姐姐听了我一番高谈阔论被我给忽悠到了。这天晚上大概9点,我正准备跑路,测试小姐姐突然找我


测试:你看看我这个代码该怎么优化一下

me:emmm..(扔给我一个js文件,467行,我统计了一下,三个if控制段,每个if带19个else,平均每一个条件6-7行的代码,就是说加起来有三四百行的代码是在重复工作)

describe ("退货分仓逻辑",function(){
    it("第三方商家、自主发货、已签收状态:退回商家地址",function(){
            var checkMap = {
                "type" : 1
            }
            var data = returnWhcode(checkMap);
            checkDataResults(data,checkMap);
    });
    // 省略19种不同的case
}

function returnWhcode(checkMap){
    //数据准备
    var info = {};
    if(checkMap.type == 1){

        info = {
            "seller" : "***",
            "status" : 7,
            "whcode" : "CPartner",
            "logistics" : "auto"
        }
    }else if(checkMap.type == 2){
        info = {
            "seller" : "5ac442c71d9771377df40c8d",
            "status" : 6,
            "whcode" : "CPartner",
            "logistics" : "consolidation"
        }
    }
    //此处省略18个else if
    var data = null;
    // 业务逻辑
    return data;
}
function checkDataResults(data,checkMap){
    caseResult.setResultMsg("商家:" + data.afterSaleMap.seller_name);
    caseResult.setResultMsg("包裹状态:" + data.info.status);
    caseResult.setResultMsg("发货仓:" + data.info.whcode);
    caseResult.setResultMsg("物流模式:" + data.info.logistics);
    if(checkMap.type == 1 || checkMap.type == 2 || checkMap.type == 3 || checkMap.type == 5 || checkMap.type == 7 || checkMap.type == 9 || checkMap.type == 11 || checkMap.type == 13){
        expect(data.afterSaleMap.return_wh_code).toBe("CPartner");
        caseResult.setResultMsg("退货地址为第三方商家地址:" + data.afterSaleMap.return_address);
    }
    // 这里当然也省略好多个else if
}

me: 这么多if-else你看着不难受么

测试:难受啊,所以来找你看看怎么优化嘛

me: 呃,要不你先说说这个测试的场景是什么

测试:测试退货分仓逻辑,根据不同的商家类型、物流模式、和发货仓库,把货物退到不同的地方,目前有20种退货组合,会分别退货到5个不同的仓库

me:明白了,就是说你现在要测一个接口,参数就那么几个,但是请求参数组合有很多种,是这样吧

测试:是哒

me: 那完全不需要把所有的请求数据全部hardcode到代码里面啊,你把请求参数抽出来,放到配置文件里面去,然后用个for循环去调用就好了

我的初版设计

{
  "第三方商家、自主发货、已签收状态->退回商家地址" : {
      "seller" : "***",
      "name" : "测试",
      "status" : 7,
      "whcode" : "CPartner",
      "logistics" : "auto",
      // 预期退货仓库
      "return_wh_code" : "CPartner",
      // 预期退货地址
      "return_address" : "上海 上海市 ***"
  }
}
describe ("退货分仓逻辑",function(){
    var whCodeInfos = JSON.parse(JsonSchemaUtils.getJsonFile(PWD+'/whCodeInfo.json'));
    for(var key in whCodeInfos){
        info = whCodeInfos[key];
        data = returnWhCode(info);
        checkDataResults(data,info);
    }
}

function returnWhcode(info){
    var data = null;
    // TODO 业务逻辑
    return data;
}

function checkDataResults(data,checkMap){
    expect(data.afterSaleMap.return_wh_code).toBe("CPartner");
    caseResult.setResultMsg("退货地址为第三方商家地址:" + data.afterSaleMap.return_address);
}

me : 你看,我们把数据和控制逻辑分离开,几百行代码一下子就变成几十行了,如果之后有新的请求组合出现,你只需要在json文件里面新增一个key-value对就好了(快夸我)
测试: 嗯,我先改好测一下看看

me: (中间经历了不少次失败,反正是折腾了很久) 十点多了,我得下班了,你写好了我明天再看看,应该还可以改进的

测试:这样很好了啊,还要怎么改进

me: 你先把这个写完,明天再看

第二天,测试小姐姐的新版

describe("退货分仓逻辑",function(){
    it("第三方商家、自营分仓",function(){
        for(var key in whCodeInfo){
            caseResult.setResultMsg("--------------分仓case分割线--------------");
            caseResult.setResultMsg("|" + key + "|");
            info = whCodeInfo[key];
            data = returnWhCode(info);
            checkDataResults(data,info);
        }
    });
});

function returnWhCode(info){
    var data = null;
    // 省略业务逻辑
    return data;
}

function checkDataResults(data,info){
    caseResult.setResultMsg("商家:" + info.name);
    caseResult.setResultMsg("包裹状态:" + info.status);
    caseResult.setResultMsg("发货仓:" + info.whcode);
    caseResult.setResultMsg("物流模式:" + info.logistics);
    caseResult.setResultMsg("期望退货仓:" + info.return_wh_code);
    caseResult.setResultMsg("期望退货地址:" + info.return_address);
    caseResult.setResultMsg("实际退货仓:" + data.afterSaleMap.return_wh_code);
    caseResult.setResultMsg("实际退货地址:" + data.afterSaleMap.return_address);
    expect(data.afterSaleMap.return_wh_code).toBe(info.return_wh_code);
    expect(data.afterSaleMap.return_address).toBe(info.return_address);
}

me:你上面的caseResult.setResultMsg("商家:" + info.name);这一串msg是需要展示到界面的么

测试:是的,我得在页面上看到结果

me: 那要是之后这个接口加了个字段,你又得来改代码

测试:没关系啊,反正只需要加两行就好了

me:白帮你优化了,可以通过改配置解决的问题,就不要改代码,像这样

我的终版设计1.0(其实后面还有一些改进,就不在这里列出来了

{
"第三方商家、自主发货、已签收状态->退回商家地址":{
    "input":{
      "seller":"5ac442c71d9771377df40c8d",
      "name":"测试redqa021",
      "status":7,
      "whcode":"CPartner",
      "logistics":"auto"
    },
    "except_output":{
      "return_wh_code":"CPartner",
      "return_address":"上海 上海市 黄浦区马当路388号小红书"
    }
  }
}
function checkDataResults(data,info){
    // 输入数据展示
    for(var key in info["input"]){
        caseResult.setResultMsg(key + ": " + info["input"][key])
    }
    // 实际结果和预期结果展示
    for(var key in info["expect_output"]){
        caseResult.setResultMsg(key + "_actrual: " + info["expect_output"][key])
        caseResult.setResultMsg(key + "_expect: " + info["expect_output"][key])
    }
    // 实际结果和预期结果对比
    for(var key in info["expect_output"]){
        expect(data[key]).toBe(info["expect_output"][key]);
    }
}

总结一下

1. 为什么会有这么多if-else

就这次测试小姐姐的案例来看,其实整个主流程的逻辑是很单一的,之所以会有这么多代码量,都是因为数据影响了控制逻辑,其实本次测试的每一个case的测试流程都是一样的,完全不需为每个case写一个条件判断。

2. 我们做了什么

其实前辈们已经提供了方向,把常改变的和不常改变的东西分开,在这个案例中很明显,随着业务的变更,这一个服务可能会产生更多的case,所以case数据是经常变动的,但是我们的接口调用流程,请求响应的整体结构是不会经常变动的。
如果对变和不变的预测没有一个好的标准,那么我这里提出一个清晰一点的方法:把数据和控制逻辑分开

3. 有什么好处

  1. 看着舒服(467行和67行,你说呢)
  2. 几乎不用改代码了
    这样就可以更专注于测试数据,不用担心改代码的时候出错,造成测试结果不符合预期
  3. 就算要改代码也会很轻松,参考第一条
  4. 接入配置中心,以后测试的时候你连代码都不用拉下来,直接在平台上就可以新增、修改case
上一篇下一篇

猜你喜欢

热点阅读