编写可测试的代码
今天在完成一项功能时,对如何编写可测试代码有较深入的思考,在此记录下。
任务背景
一项功能由登陆后的通知触发,界面UI是异步刷新的,具体入口功能是否可用还依赖于其他两个指令(这里以A、B指令为例),整体流程大致如下:
- 收到登陆通知,发送A指令
- 在A指令的响应内容中,判断是否需要发送B指令,如果需要,则发送B指令,如不需要,则功能不可用,用户在操作时,弹错误提示A
- 收到B指令的回复,回复内容中有两种情况:允许操作和不允许操作。
- 如允许操作,用户可以打开功能,如果不允许操作,用户在操作时,弹错误提示B。
任务目标
产品提出需求是:当用户在任意情况下点击,在不同场景下,弹出不同提示。
解决方案设计
在最开始的时候,产品人员没想到如此多的情况,只给出错误提示AB两种场景,如果简单照着产品人员的需求来做,那这就很简单,不需要考虑网络异常的情况,但和项目经理商量了下,觉得有必要把请求响应过程中的一些情况给区分开,处在不同状态下,应该要有不同的提示,这便于开发分类处理和测试反馈。
就上述这个问题来说,如果更为细致地划分,大致有如下几种情况:
- 发送A指令前
- 已发送A指令,等待A指令返回超时
- 已发送A指令,后台响应出错
- 已发送A指令,后台响应正确,返回内容指示无需发送B指令
- 已发送A指令,后台响应正确,返回内容指示需要发送B指令,立即发送B指令
- 已发送A指令,等待B指令响应超时
- 已发送A指令,B指令返回出错
- 已发送A指令,B指令返回正确,不允许用户操作
- 已发送A指令,B指令返回正确,允许用户操作
在前后台交互中,每一步都有可能出状况,UI层需要在不同请求场景下响应不同的提示语。如果从程序流程处理的完备性上来讲,上述如此多的情况,是需要明确一一对应状态吗,UI根据不同状态码,提示不同的内容。
想到这里,我心里就在想,产品经理在考虑这个业务流程时,肯定不会考虑到如此多异常情况,否则,他就不是以产品视角去看待这个业务,而是从开发的视角去看待。如果是从测试的角度来测试这项业务,那么,在测试案例中,就会有上述这几种情况下的测试需求了。而产品又不可能在初始设计时就枚举出如此多的场景,这下就尴尬了。
从工作流程上来看,产品输出需求文档,交由开发,开发根据文档实现功能,交由测试。产品是面向业务设计,测试是面向功能点测试,而开发起到承上启下的作用,将业务梳理清楚,将组成业务的功能点一一实现。从这一点上看,强势的开发实际上是在帮助产品测试需求文档,弱势的开发则只会照着需求文档里要求的来做,当遇到一些不明确的功能点的具体处理时,A做法也行,B做法也行,但功能实现了,但对外表现不一样,这会造成测试在测试业务时下无清晰明确的参照,所以说,作为一个专业认真的开发,在着手编码前,一定要和产品人员撕逼,讨论清楚需求,将一些模棱两可的点掰扯清楚,以文字的方式记录下来。
上面扯远了,回到本文提到的问题上。细致分析,上面一共有9种情况,从开发角度来模拟这些情况很简单,比如情况1,执行流跑到这里,让他直接跳过后续流程,系统就处于状态1了,其他的情况类似。但是,测试人员无法控制程序的执行流程,他们只能从网络层面或者后台层面给与适当的控制,这会造成无法构造出连续请求的中间状态,也就无法触发这些分支下的错误提示。
从开发角度来看,开发说,我考虑了这么多情况,是测试不给力,没测到这条分支。
从测试角度来看,测试说,我咋知道当网络断开时,程序是跑到哪个状态下了,只能测几种情况,测不了其他的情况。
这就在程序中潜藏了一条 "没走过的路", 这条路背后是悬崖还是坦途,测试不知道,开发虽口头上说知道,但实际在跑起来的时候,心里也没底,会不会有那么巧的网络状态,恰好满足发送A指令时,网络是正常的,但紧接着发送B指令时,网络就断开了呢?不清楚,谁也不敢拍着胸脯说,这种场景绝对不会出现和绝对会出现,只不过这种出现的概率很小吧了。
结论
经过仔细谨慎的考虑,从便于测试的角度触发,去掉一些不可能构造出来的测试场景,简化处理。
编写可测试的代码,不仅仅要从开发人员的角度出发(比如单元测试、集成测试),更要从测试人员角度出发,在目前的测试环境和测试手段下,是否有能力构造出这样的场景来测试对应的逻辑分支。
与人方便就是于己方便,少挖坑,多填坑。