卡牌对战自动化测试框架设计实践
目录
一、背景
项目从0到1点时候,都是手工测试的,经历了多轮改一发坏全身。可想而知,未来要加新机制或调数值的话,如果还用传统测试方式,会非常低效:
- 修改一点效果就需要重复回归大量组合
- Buff、护甲、伤害、回血、摸牌等复杂联动容易漏测
- 数值调整后缺乏系统化验证手段
- 特定出牌顺序的case需要一定运气
如果没有自动化测试框架,后续所有平衡性调整都会越来越危险。
二、不只是“测试脚本”
我不希望只是简单写几个接口调用,我希望是一个可编排、可断言、可扩展的“测试引擎”。
输入:
- 卡组配置
- 测试步骤 DSL
- 状态断言规则
输出:
- 自动执行测试
- 状态验证
- 每步结果日志
- 批量回归能力
三、整体架构设计
1.配置层(DSL)
测试用例使用 JSON 描述:
{
"deck1": [...],
"deck2": [...],
"academy1": 1,
"academy2": 1,
"procedure": [...]
}支持卡组配置和行为流程(出牌、结束回合、防御/跳过防御、状态断言)
示例:
[
{"action":"play","player":1,"card":"xxx1"},
{"action":"play","player":1,"card":"xxx2"},
{"action":"assert","player2":{"health":7}}
]实现了用配置描述测试,而不是写测试代码。
2.初始化
核心流程:
- DSL 直接写中文卡牌名便于维护,因此初始化时需要将其转为内部 CardId
- 构建双方卡组
- 不洗牌
- 其他流程,直至对局开始
其中不洗牌这件事非常重要,需要改造游戏逻辑代码,加一个控制洗牌的参数。不洗牌才能让双方起手固定、抽牌顺序固定,从而测试结果可复现。
3.执行
包装 WebSocket 数据,固化成几个简单函数,便于维护。
PlayCard()
EndTurn()
SelectCard()
SkipDefence()
CoinThrow()
Surrender()其中,有个场景判断函数非常重要:JudgeRobotScene(),可以保证:
- Main阶段才能出牌
- Defense阶段才能防御
- Select阶段才能选牌
从而在工程上防止非法调用。
此外还有一些简单的 Retry机制,解决网络抖动、同步延迟等问题。
4.状态验证
当前支持:
- 血量
- 护甲
- 能量
- Buff存在性
- 手牌数量
- 牌库数量
- 手牌费用
采用客户端视角和服务端真实状态双状态源验证。
四、测试执行完整流程
当前完整闭环:
Load DSL
↓
Build Deck
↓
GameInit
↓
Connect Players
↓
Wait Game Start
↓
Execute Procedure
↓
Assert State
↓
Generate Result五、优势总结
1.支持批量测试
DoTest("testdata/*")可用于:
- 全量回归
- BUG复现
- 新卡专项测试
- 卡组专项测试
2.固定牌序
去除了自动化测试的随机性。而且有特殊用法,想构造特定的测试场景人工看的时候,也可以用这套方法,执行到想看的场景,然后人工进入 UI 的正式游戏中接管操作。
3.DSL可扩展性强
未来新增其他操作和断言非常方便,而且不影响老用例。