1.5.3用完即抛
笔者在团队中一直倡导的一个测试设计原则是“测试环境是短暂的(Testenvironmentisephemeral)”。一个长期存在的测试环境不可避免地会出现各种问题,如脏数据、累积的测试数据未清理、配置的漂移(Drift)等。这些问题都会严重影响测试的稳定性。虽然可以通过数据清理、配置巡检等手段解决这些问题,但彻底的解决手段是每次都按需创建新的测试环境,用完后即销毁。
测试环境用完即抛的好处如下:
解决环境问题,减少脏数据。
提高可重复性(Repeatability),确保每次测试运行的环境都是一致的。
倒逼各种优化和自动化能力的建设(测试环境的准备、造数据等)。
提高资源使用的流动性。在实际的物理资源不变的前提下,增加流动性就能增加实际容量。
“测试环境是短暂的”就意味着:
(1)我们的测试环境搭建能力要很强。搭建新测试环境要快速、可重复、成功率高、无须人工干预,要能可靠地验证搭建出来的新环境是不是好的、是否满足后续测试的要求。
(2)我们的测试策略和自动化的设计必须不依赖一个长期存在的测试环境。例如,不依赖一个长期环境里的老数据进行数据兼容性测试。
(3)日志要打印好。测试环境一旦被销毁,保留下来的就只有应用代码打印的日志(一般保存在ELK、SLS等日志服务中)和测试自动打印的测试输出。这些日志和输出要详细、清楚,目标是绝大多数的测试用例失败都能通过分析日志定位到问题。我们经常说的一个原则是写日志的时候,要假设以后“日志是你唯一的问题排查手段(Logasifthat’stheonlythingyouhave)”。
有时候,测试环境用完后的确还需要保留一定时间。对这样的需求,我们也要设置一个比较短的时间上限,例如:
一个测试环境的默认有效期是48小时。
到期可以申请延期,每次延期最多可以增加24小时(newExpTime=now+24h,而不是newExpTime=currentExpTime+24h)。
最多可以延期到7天(从创建时间开始算)。对于需要7天以上的,要走审批流程。
这样做的好处就是倒逼。一刀切的倒逼在一开始会有点儿痛苦,但大家很快就会习惯,自动化等环节很快就跟上了。
测试环境用完即抛的确会引入一些新的质量风险。如果有一套长期维护的环境,里面的数据是老版本的代码生成的,那么部署了新版本的代码后,这些老数据是可以帮我们发现新代码里面的数据兼容性问题的。现在用完即抛,没有老数据了,这些数据的兼容性问题就可能无法被发现,这个风险的确是存在的。控制这个风险的思路是往前看,而不是往回退。我们要探索数据兼容性问题有没有其他的解法,有没有其他的测试或者质量保障手段。甚至要想一想,怎么做到“从测到不测”,通过架构设计解决数据兼容性问题,让它不成为一个问题。
1.5.4不自动重跑
很多团队都会在他们的测试平台里增加一个自动重跑的功能:在一次完整的测试执行后,对其中失败的用例自动重跑一遍。如果一个用例的重跑通过,就把这个用例的结果设为通过。
这个做法是不好的,自动重跑虽然在短期内能(在表面上)提升测试(结果)的稳定性,但长期来看,对整个团队、质量、测试自动化都是有害的。自动重跑会使得工程师不再深入地排查问题、揪出隐藏很深的Bug。因为工程师的时间都是有限的,既然一个用例已经被标为“通过”了,即便只是重跑才通过的,那么工程师也没有必要仔细看。这样就可能漏过一些真正的Bug。在这类“第一次会失败,重跑会通过”的问题里,笔者印象最深的一个Bug是GUID值的处理代码。这段代码只有在GUID串的第一位是一个特定的字符的时候才会触发Bug,引起测试用例失败。因此,这个测试用例的失败概率是1/16,而且在重跑时很大概率是会通过的。
有一些用例不稳定的根本原因是系统的可测性问题。有了自动重跑以后,反正用例重跑一下还是能通过的,所以工程师就没有动力改进系统的可测性了。
由于前面两点,深层的Bug没有被揪出来、本质性的问题(例如可测性)没有解决,问题慢慢地积累、蔓延,测试运行后需要重跑的用例越来越多,导致测试执行所需要的总时间越来越长。
对于“确定型”的被测系统(例如支付、电商、云计算等)来说,系统行为是确定的,因此测试的结果也应该是确定的。对被测系统来说,关闭自动重跑,一开始可能比较痛苦,失败的用例数会很多,但只要坚持下去,梅花香自苦寒来。