
做信创测试这几年最让我意外的从来不是功能跑不通而是那些只有在异常场景下才冒头的诡异故障。某次适配测试业务程序在x86环境里连续跑48小时都没事迁到国产操作系统的ARM服务器后只要模拟一次突然断电再重启业务进程就起不来数据库里还残留了半截写入记录——最后定位到应用初始化时根本没处理文件系统日志回放不完整的情况。这种问题光靠功能用例根本测不出来。正常路径跑得通只能证明系统“能用”异常场景扛得住才能证明系统“扛用”。信创测试里的异常场景设计就是主动把CPU、内存、磁盘、网络、时间、外部依赖这些环节逼到极限或者直接弄挂然后看软件在国产CPU、国产操作系统、国产数据库这套组合下能不能自我恢复、能不能保住数据。这篇内容适合正在做信创适配测试、验收测试的同学也适合给测试方案做评审把关的人看我会从设计方法、故障注入、验证链路、自动化回归四个角度讲清楚尽量把可以直接抄作业的细节都放出来。1. 信创测试里最容易漏掉的一环为什么异常场景不能靠“顺手测”1.1 功能测试和异常场景测试本质上是两个平行世界功能测试验证的是正常路径的正确性用户登录、点按钮、提交表单、拿到正确结果。异常场景测试验证的是非正常路径的可恢复性资源枯竭、依赖失效、输入恶劣时系统会不会坏得没有底线。我用开车来类比功能测试好比在直道上加速、在停车场倒库练的是正常驾驶技能异常场景测试好比模拟爆胎、刹车失灵、雨夜视野丢失练的是极端情况下能不能平平安安开回维修站。一辆车如果爆胎就翻它即使平时跑得再顺也不能说安全。软件也一样平时再顺磁盘满了就崩、断网就死循环放在生产里就是一颗定时炸弹。在信创测试里很多团队把“兼容性适配”理解成“功能用例能跑通就行”这是最大的误区。适配只是第一步国产化软硬件栈整体组合多、行为差异大异常场景才是真正拉开稳定性和可用性差距的地方。我见过不止一个项目验收测试阶段全部功能用例通过结果上线第一次磁盘告警就把进程搞挂了原因就是没人测过资源耗尽场景。1.2 信创环境下的异常既有共性也有“全新个性”任何IT系统异常类型翻来覆去就是那几类断电、断网、资源耗尽、进程被杀、外部依赖失败、异常输入。这部分是共性的普通测试方法也能覆盖。但信创环境真正的难点在“个性”CPU从x86换成了ARM或者其他自主指令集操作系统从Windows换成了国产Linux发行版数据库从常见的商业数据库换成了国产数据库。每一层替换都会让同样的异常产生不一样的表现。我举一个实际遇到的差异同样是磁盘写满在x86平台上应用通常会捕获写入失败并抛出一个可处理的错误程序还能继续响应部分请求但在某个ARM平台上同样的写入失败直接让进程hang住一等十几分钟不响应。原因不在业务代码本身而是底层文件系统、驱动和内核配置的参数组合不同。这个差异只有在信创平台上真实注入故障才能暴露。所以异常场景设计不能把旧的测试用例直接搬过来必须带着信创软件栈的上下文重新审视同一个故障点在国产平台上预期表现是什么哪些地方会成为新的薄弱环节这决定了后续验证方法的设计深度。2. 设计维度别只盯着“功能跑通”从数据、资源、环境三条线切进去2.1 数据层面的异常从编码、边界到数据库特性数据是异常的“重灾区”在信创环境里尤其严重。首先要注意字符集和编码国产平台很多业务表单带着中文、GB18030编码或者不同系统之间用不同编码传递数据。异常设计时至少要考虑非法字节序列、字符集不匹配、超长字符串截断、大小写敏感排序、null值参与运算这些输入。数据库行为差异也得重点照顾。国产数据库对大小写、空值、隐式类型转换的处理跟业界常见商业数据库往往不完全一致。比如某些国产数据库在where条件里对null的处理行为不同一条原本正常的SQL迁过来可能直接走到全表扫描或者返回错误结果。设计异常用例时要把这些边界输入作为独立场景列出而不是混在常规功能用例里顺手带过。2.2 资源层面的异常磁盘、内存、CPU、句柄都得考虑资源耗尽最容易触发“雪崩式”故障。每个资源类别不能拍脑袋就写一个用例而是要去想真实业务的依赖顺序。磁盘层面临时目录写满、日志分区写满、事务日志目录只读内存层面堆内存耗尽、进程被OOM-Killer杀掉CPU层面打满之后任务积压、超时失效句柄层面文件描述符耗尽、数据库连接数满。对信创平台还要额外关注一点很多国产Linux发行版的默认配置偏保守文件描述符上限、swap分区大小、内存回收参数可能和之前团队熟悉的平台不一样。同样一套业务代码以前启动10个线程池没问题的迁过来可能因为默认配置就频繁触发资源限制。这些都要设计成显式用例验证而不是等上线了靠用户发现。2.3 环境与接口层面的异常网络、时间、权限、外部依赖软件不是孤岛。网络层面的异常至少要覆盖断连、丢包、高延迟、乱序重传时间层面的异常包括时区设置错误、时间回拨、向前跳变这两类都可能引发证书校验、定时任务误触发、日志时间戳混乱等问题权限层面的异常包括只读文件、无权限目录、用户被锁定、sudo权限缺失外部依赖层面的异常包括中间件宕机、认证服务不可达、第三方接口超时、数据库主备切换。这些异常在设计上有个共同点最好从“依赖方的视角”设计预期结果。比如第三方接口超时业务是重试三次后快速失败还是无限制阻塞数据库断连之后连接池是立即重建还是把请求全部打满这些预期结果必须写进用例否则验证环节就没有判定标准。3. 可直接落地的异常场景设计样例与故障注入方法3.1 拿来就用的异常场景设计样例下面这张表是我在项目中经常直接套用的基础模板覆盖了信创测试里最高频的几类异常。第一列表示例类型第二列是故障构造手段第三列是你要设计的预期验证点第四列是信创平台特有的注意点。异常类型构造手段预期验证点信创平台注意事项磁盘空间耗尽用dd命令填满业务分区观察写入失败应用能否捕获异常、清理临时文件、恢复后继续服务确认填的是业务分区而非系统根分区防止污染整个测试环境内存耗尽压力工具持续占用内存直至触发OOM进程是否被杀、是否有优雅退出或重启、内存回收是否干净部分国产系统默认swap为0OOM触发更快判定标准要提前定CPU打满压力工具压满所有核心慢请求是否积压、超时机制是否生效、任务队列是否失控ARM平台核数多少差异大先核对该机器核数拓扑再设计压力大小数据库断连直接kill数据库会话或重启数据库服务连接池重试、事务回滚、业务是否快速降级国产数据库连接状态检测方式不同需确认探活机制是否支持网络丢包/断连断网或用防火墙规则模拟部分丢包重试是否指数退避、补偿任务是否执行、是否产生脏数据部分国产发行版默认防火墙策略有差异模拟前先理解默认规则动态库缺失用ldd确认依赖后重命名so文件启动失败报错是否清晰、启动过程是否安全退出国产平台动态库依赖树可能不同于传统惯例重新整理依赖清单3.2 故障注入手段命令、工具和更细的技巧故障注入不要只想着“搞挂它”要把异常做得足够真实、可控、可逆。这里给几个我常用的具体操作。磁盘满的构造思路是先看分区再填充最后释放。先用df -h确认当前挂载点和剩余空间选定业务数据所在的分区然后执行df -h dd if/dev/zero of/tmp/fill.img bs1M count5000等到应用开始报写入失败时说明空间已经耗尽。此时不要急着清理观察应用在持续几分钟内的表现记录日志和进程状态。验证完后删除填充文件rm -f /tmp/fill.img这样能同时验证两个事情应用在磁盘满时怎么表现磁盘恢复后能否自动继续写入。页面内存和CPU压力可以用stress-ng这类通用工具来做不是所有国产发行版默认都装了它没有的话可以换用一段简单的脚本来模拟内存分配或者直接写一个循环数组程序。数据库断连比较推荐直接kill会话不要只在客户端关闭连接那样测不出连接池的重建逻辑。网络异常可以用防火墙规则对目标端口做随机丢包比例从1%到10%分档模拟比单纯拔网线的结果更贴近生产。时间异常是很多人会忽略的。操作时先记录系统时间基线再用date命令同时调整系统时间和硬件时间比如把时间往前拨两个小时观察定时任务、日志时间戳、证书校验是否异常。测试完必须校准回来否则整个测试环境的日志和证书全部乱掉后续用例全废。3.3 构造异常时最容易忽略的三个细节第一个细节是“注入前的基线快照”。任何故障注入之前我先记录三样东西业务的正常响应时间、进程的资源占用、数据库关键表行数或校验和。没有基线异常恢复后你根本说不清数据是不是真的没丢、性能是不是真的没退化。这个习惯比任何工具都重要。第二个细节是“异常持续时长”。很多用例只设计“异常出现”和“异常消失”两个点忽略了异常持续时长的影响。磁盘满10秒和磁盘满10分钟行为可能完全不同。设计时最好给每个异常场景加一列“持续时长”用同一份用例跑三个梯度比如30秒、5分钟、30分钟对比系统的自愈能力和疲劳表现。第三个细节是“级联异常的观察”。磁盘满常常先引发日志写失败再触发服务降级然后导致大量重试请求把CPU打满。验证时不要只看第一层症状要顺着链路记录后面30分钟内有没有次生故障。很多测试人员看到第一个报错就急着恢复环境反而把最重要的根因证据给弄丢了。4. 验证阶段的核心一条可复现的排查链路和常见信创平台疑难杂症4.1 排查链路拿到故障现象后按这个顺序走验证异常场景时第一步不是改代码而是收集证据。我习惯按“三看一复现”走。一看应用日志重点找未捕获异常、错误码栈、线程卡死位置。二看系统日志用journalctl和dmesg找OOM记录、驱动报错、信号杀进程记录。三看资源快照内存、磁盘、句柄在当前时刻的实时状态。证据齐全后再做复现实验同样的异常注入一次、两次对比前后差异。这一步在信创平台尤其重要。故障的表现经常“长得像应用问题实际是平台问题”比如某个异常退出看起来是进程自身crash但dmesg里其实记录了硬件中断异常或驱动超时根因在底层。没有系统日志佐证很容易让开发团队在业务代码上瞎折腾一周。4.2 信创平台上我踩过的那些“隐形地雷”字符集和时区是两个高频地雷。部分国产发行版默认区域设置可能不是UTF-8启动脚本里一旦按旧平台习惯写死某种编码中文日志直接变成乱码数据库写入也容易出错默认时区可能是UTC和业务使用的北京时间差8个小时定时任务全部错位。处理方式是把字符集和时区纳入环境基线检查清单任何机器部署前先校验。Shell和动态库的差异也不能小看。有些发行版默认sh指向dash而不是bash脚本里用到数组、[[ ]]这类bash特性的跑起来就报错。动态库方面有些第三方库在国产平台上没有预编译版本只能现场编译编译出来的依赖树跟传统平台完全不同测试环境必须与应用环境使用同一套依赖版本。还有两个非常容易踩的默认设置coredump默认可能关闭进程一崩什么核心文件都不留排查难度立刻翻倍文件描述符和进程数上限偏低并发稍高就触发资源限制。这些都要在测试开始前改好并写进文档否则后面所有异常场景的验证结果都失真。在开始大规模异常场景测试前先花半天写一份环境基线检查清单把字符集、时区、ulimit、coredump开关、swap大小全部固定下来。这一步省下来的排障时间一定大于检查耗时。4.3 怎么判定异常场景算“通过”分级的通过标准异常场景测试必须有量化的判定标准不能出现“看起来好像没崩”这种结论。我习惯分成三级。等级异常期间的业务表现恢复方式数据一致性处理建议A级自动降级用户基本无感自动恢复完全一致保持现状B级部分功能不可用人工介入或明确恢复机制最终一致优化恢复时长C级功能不可用或崩溃无法自愈损坏或丢失缺陷修复判定时除了看能不能恢复还要检查四个点数据一致性用校验和、行数对比、对账任务来验证进程残留用ps查僵尸进程和孤儿进程锁是否清理要查数据库锁和文件锁告警是否有效要看错误码、日志上下文是否足够定位。任何一项不满足都不能算通过。5. 让异常场景回归常态化覆盖率度量、自动化落地与风险定级5.1 覆盖率怎么算用场景矩阵代替拍脑袋异常场景设计最怕“想起来什么测什么”。我习惯先建一张覆盖矩阵横轴是异常类型包括资源、数据、环境、接口纵轴是受影响的对象包括登录、订单、文件、数据库、定时任务、外部接口交叉点就是潜在场景。再用信创栈特性做一层叠加比如“这个对象是否依赖国产数据库特有行为”“是否运行在ARM指令集下”。每个交叉点不需要全测但高风险点必须覆盖。我一般按三档控制关键业务对象的所有高风险异常至少覆盖80%中风险覆盖60%低风险覆盖30%。每周统计一次覆盖变化用新增缺陷数和恢复时长作为效果指标比空喊“加强测试”实在得多。5.2 自动化把异常场景跑成固定回归项异常场景不能只在新项目适配期做一次上线后每次版本回归都应该抽关键场景再跑。自动化是唯一可持续的路。工具选型上我不迷信重型平台先用通用手段落地shell脚本控制注入Python脚本封装断言CI流水线定时触发。关键是脚本里要包含三个要素注入前的基线采集、注入动作、注入后的恢复验证三个环节缺一不可。测试环境建议做成快照每次跑完直接回滚避免环境脏掉影响下一轮。信创平台上要注意一个问题很多测试工具和Agent没有ARM等新指令集架构的官方支持强制装上可能运行异常。我的做法是先列“最小可用工具集”优先选择有官方新架构支持的工具没有就自己写脚本替代保证CI机在国产平台的执行结果可信。自动化脚本里的注入动作要可逆命令本身要注意超时和幂等避免CI上跑一次就把环境搞坏。宁可多花半小时做环境回滚也不要让异常场景测试污染了后续用例。5.3 风险定级与回归优先级把好钢用在刀刃上异常场景数量可以很多但测试资源永远有限必须做风险定级。高风险涉及数据一致性、主流程不可用、资金或核心业务正确性的场景比如数据库断连、事务日志满、主备切换中风险功能可降级使用的场景比如第三方接口超时、缓存失效低风险仅影响体验的场景比如某些非关键日志乱码、提示文案缺失。高风险场景每次发布前必须回归中风险场景按月或按特性变更回归低风险场景在季度全量回归里顺带覆盖。我在团队里有一条很朴素的规则宁可减少功能用例的数量也不能砍掉高风险异常场景。功能bug通常会在多轮测试里被发现异常场景埋的雷经常是上线后才炸。我个人的另一个体会是把磁盘占满、时区错位、数据库断连这三个场景直接写进所有项目的每次发布前必跑列表已经帮我提前拦下了好几起潜在事故。异常场景设计这件事越早做后面的验证、定位、修复就越从容。