作为一个懒惰的程序员,要自动化一切,包括游戏测试。

游戏是一个复杂的CS系统,本身的数据流是二进制的,不像网页那样的文本制好解析;画面和UI是基于DX的,也就不能用一些测试通用窗口控件的工具去测试游戏。

我尝试过一些从各方面借鉴的做法。

单元测试

很多年以前,我在寻仙项目上尝试了单元测试。基本借鉴了《修改代码的艺术》一书,对C++进行单元测试。C++不同于脚本语言的动态性,mock的时候需要花费较多的精力,但进行单元测试是可行的。

我对服务器部分的一个组队模块部署了单元测试,但是接口和模块功能变化太频繁,很快就不再维护了。

协议测试

再一次的考虑自动化测试是在刀2项目。这一次依赖的是机器人工具和脚本,做了一个极简的客户端,让这个客户端可以通过脚本登陆、退出和收发所有消息,然后在脚本中定制测试流程。

这套工具听着蛮不错的,至少能测试服务器真实的交互流程,QA也用过一段时间,用来测压力和刷怪。但说到测试某个子模块,却一直未能成形。

其实还是老问题,通信协议太容易变化了。今天这个子模块还好好的,明天可能就某个协议增加了字段或者调整了发送顺序,测试就挂了。

这样一来,调整太频繁,可用性就低了。

rspec

最近在学习ruby on rails,相应的也就接触到rspec测试,很快就有了灵感,觉得这可能是一个更靠谱的方向。

rspec把整个页面作为测试对象,通过填充和点击操作,验证页面刷新包含的目标字符串。页面其实就是DOM文本,前面说到游戏从里到外都是二进制的,视觉内容还真不是一般工具能检测和操作的。

虽然如此,但是灵感就从中抽象出来。UI模块虽然是私有的二进制数据集合,但实际上对我们而言就是一棵控件树,在客户端的脚本里,同样可以用类似rspec的方式去操作UI,并且检验结果。

为了降低功能的频繁调整而降低测试的可用性,测试脚本一定是要把UI当做黑盒,尽可能用稳定的接口。用类似rspec的语法写个测试游戏商城模块的例子:

describe 'mall' do
    click_button ui_main.w_main, '商城'
    wait 2, seconds
    
    assert ui_supermarket.w_win.visible
    assert { have_content ui_supermarket.w_win, '圣甲精华' }
    
    click_button ui_supermarket.w_win, '购买', '圣甲精华' }
    assert ui_msgbox.w_win.visible
    
    fill ui_msgbox.w_win, '数量', 1
    click_button ui_msgbox.w_win, '购买'
    wait 2, seconds
    
    assert { have_item('圣甲精华', 1) }
end

测试的流程大体是打开商城界面,点击圣甲精华购买按钮,出现购买确认对话后,填充数量并发起购买,然后确认道具数量的变化。

虽说把UI当黑盒,但窗口的顶层控件作为参数会有利于测试加速。比如 have_content 就是在商城窗口中搜索圣甲精华文字,至于这个文字到底放在哪,则一层层的去搜索商城窗口的子控件去寻找了。

无视UI的布局细节,尽量从客户端本身的数据中,通过不易改变的名字去查找和验证,就不惧怕程序的频繁调整了。