本帖最后由 ervinzhang 于 2015-5-21 20:22 编辑
犯罪是普遍的,而逻辑则是难得的东西。-福尔摩斯
我坚定不移的认为一个优秀的[url=]测试[/url]一定是一个优秀的侦探,测试的过程则是侦破案件过程,拨开层层迷雾,凭借细微的点滴线索寻找着隐藏在代码背后的bug,真相只有一个! 下面的这个案件在侦破的过程中困难重重,各种谜团环环相扣,尽管过去了很久,笔者依旧记忆清晰,让我们一起回到2014年的夏天,一起拨开层层迷雾,重温谜雾背后的真相。
笔者当时供职于DHD侦探事务所,那是一个阳光明媚的日子,强烈的阳光穿透过水泥森林拷打着世间万物,麻雀们在叽叽喳喳的飞来飞去,无来由的内心有一丝莫名的伤感,作为侦探的第七感告诉我,有大案子要发生了。果然,来到事务所后,笔者被告知有个重要的案件需要尽快侦破,事务所所长非常重视,限期破案,而且别的侦探都在忙别的案子,只能由笔者来扛了。既然如此,只能硬着头皮接了。
作为一名老侦探,我把侦破做了个简要计划,计划如下: 详细阅读卷宗(至少3遍)->就卷宗疑点与犯罪嫌疑人沟通确认->推演犯罪过程->解决谜团->揭露真相
卷宗如下:为了不必要的误解,我省略了大部分对读者无意义的描述,只陈述下案件简介,案件描述如下:在游戏中添加竞技场功能,要求用户能够与机器人或者真实用户竞赛,并通过竞赛获得一定积分,积分用来兑换奖励。
笔者仔细阅读了卷宗,发现有几个疑点如下: 疑点1,案发现场:密室还是开阔空间(直接展现型功能还是入口跳转型功能)? 疑点2,犯罪时间:特定时间还是循环时间(一次性永久功能还是带有cd时间的循环开启功能)? 疑点3,罪犯展现:罪犯的特征描绘(功能涉及的UI,UE,资源等) 疑点4,犯罪手段:犯罪的各种手段(开启条件,上场设置,胜负表现等) 疑点5,涉案资产:罪犯非法获益(资源产出,兑换等)
经过仔细阅读卷宗及与犯罪嫌疑人反复沟通确认,本侦探终于将以上各个疑点清楚,得到基本的犯罪事实如下: 1,本次犯罪为开阔空间犯罪,入口有多个,分别如下:建筑物入口,UI按钮入口,锦标赛条目入口,各条巨龙建筑入口 2,犯罪事件为循环时间,竞技场每次循环时间为1天,可通过配置来设定 3,犯罪展现:用户可以拖动每条龙来选择是否参站,每次参展消耗一张门票,门票每日免费赠送5张,用完后可消耗游戏内宝石购买。 4,犯罪手段:竞技场每日固定时间开启,用户需具有8级以上龙才能参展,否则提示玩家去升级巨龙。 5,每次战斗胜利或失败后,玩家的积分将会发生变化,积分可用于兑换道具
基本犯罪事实理清后,我们一起来继续推演和还原犯罪过程,来看一下犯罪过程中会出现什么样的未知谜团及如何攻破这些谜团。
谜团1:犯罪的自我陈述与实际情况不符(匹配规则与实际匹配结果不符),那么我们只能去理清犯罪的内在逻辑,看看问题到底出现在什么地方,本侦探把逻辑画成了2张图表,见下
通过这2张图,本侦探仔细演算了匹配结果,发现犯罪嫌疑人对轮数这个重要参数的理解有误,计算公式错误,重新调整公式后,计算结果正确。
谜团2:卷宗内数据记录不正确(db中存储的数据有误差),怎么知道犯罪嫌疑人(开发人员)说的是真实的呢?真相只基于遇独立思维来获得和验证,本侦探又根据卷宗自己推演了犯罪过程,拿我的推演结果来与犯罪嫌疑人的描述来做对比,推演过程如下(脚本): 积分计算脚本(根据策划文档独立于开发人员的思维来书写) #! /usr/bin/env ruby K = 12 #当前系数,如改变需自行变更 rn = 0 def count_we(elo_fighter,elo_definder) we = 1.0/(1+10**((elo_definder.to_i - elo_fighter.to_i)/400.0)) return we end puts ("please input the fighter's elo value:") elo_fighter = gets puts("please input the 1st definder's elo value:") elo_definder1 = gets puts("please input the 1st battle result(win 1, failure 0, tie 0.5):") w1 = gets w = w1.to_i we = count_we(elo_fighter,elo_definder1) rn = elo_fighter.to_i + K*(w - we.to_f) puts "the new elo value of fighter is: ",rn.to_i
根据我们的独立思索和推演,结果与犯罪嫌疑人供述存在不一致的地方,最终对比计算公式,发现犯罪嫌疑人计算某个数值时用的是整型的数据类型,导致某些计算结果中的小数被忽略,从而导致最后数据存在误差。经过详细推演与仔细比对,这个谜团也解决了。
谜团3:犯罪细节。对于一种新类型的战斗,我们如何确认战斗数值的准确性呢?尤其是涉及到buff、物理伤害与魔法伤害混合使用的时候?犯罪嫌疑人给出的犯罪过程一定是真实的么?对于这些不确定性的黑盒,我们只能顺着一条条线索逐渐核实,线索繁琐,笔者为不耽误大家的时间,举其中某一条线索为例: 护盾buff: Numerica = life*(skill_affect_args)(skill_affect_args是在dragon_skill_values.json文件中配置) @absort_num = numerica def effect(event,attack_info) if attack_info[:taken_damage] >= @absort_num attack_info[:taken_damage] -= @absort_num @absort_num = 0 set_died 结束回合 end 通过这条线索,我们知道如果伤害大于护盾,则最终伤害值等于初始伤害值减去护盾值,如果伤害小于护盾值,则最终伤害值等于0且护盾次数减少1次,伤害结算后,本回合结束。基于这条线索事实,我们就可以设置不同的犯罪条件来验证结果,通过多次验证,护盾线索被证明正确。
谜团4:犯罪过程中的先后顺序,犯罪推演中,不同的顺序往往导致不同的结果。我们还是举个例子:加血buff def most_need_heal return false if all(true).size == 0 all(true).min_by do |d| d.cur_life * 1.0 / d.life end end
我们来看看这个犯罪过程中的顺序如何,通过对这段代码分析,我们得知加血会在队友中寻找血量剩余百分比最低的一个单位去加血,此处注意细节,不是血量值最低,而是血量百分比最低。 基于以上推理,我们即可设置不同的条件来验证加血规则是否正确。
谜团5:趋势性犯罪是否存在?战斗发生有限几次的正确性能否代表战斗发生数万次后的正确性?低等级单位战斗随着等级的提升战斗力的提升是否符合预期?这些我们都不能忽视,需要给出具体的趋势结果来帮助分析案件。 以下图为例,本侦探通过数据统计,分析出每个战斗单位的战斗力的提升趋势。 通过与犯罪嫌疑人(策划)核对,符合犯罪嫌疑人的供述(需求设计预期)。
通过这次案件的侦破及以前的多起案件侦破过程,本侦探总结了几条侦探大法,与诸君分享: 1,永远不要相信犯罪嫌疑人(程序员或策划),保持独立思考 2,犯罪嫌疑人会经常翻供,做好心理准备,时刻根据翻供(需求变更)调整侦破思路 3,线索永远是有限的,合理的推理则是无限的(拓展测试广度和深度) 4,犯罪(bug)需要被确定性的验证 5,长期犯罪(趋势性bug)经常被忽略 6,旧有的卷宗(需求,用例,总结)存在不确定性,需要结合实际的变更不断更新维护 7,存在于特定临界点(边界值)的犯罪危害最大 逻辑不死,真相永恒! |