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

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


最近测试小姐姐在写自动化测试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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,198评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,334评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,643评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,495评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,502评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,156评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,743评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,659评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,200评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,282评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,424评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,107评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,789评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,264评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,798评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,435评论 2 359

推荐阅读更多精彩内容

  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,744评论 2 59
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,693评论 18 139
  • 图文/2016冰山来客 窗与日月同启 风是思绪的源泉 将依恋落在青春的笔端 书写一卷诗意的心 ...
    2016冰山来客阅读 402评论 0 4
  • 西秦木子抒情诗集《守望者》目录 你的影子总在前面飘过 掀起一股微风 洞穿我的大脑 刷新界面 或升级版本 与天地相通...
    西秦木子阅读 250评论 0 4