首先是项目代码:statAd是我的功能模块API,他的功能定义是累加某个广告在某个投放位置的pv和uv(存到一个全局数组LIST里)
详细说明:pv的概念大家很清楚就是浏览广告的人次,uv的概念则是某个时间段内,浏览过的人数(非人次,一人浏览多次算多个PV但只算一个UV);输入其实是已经经过初步计算的数据,它标识了一个人在某个页面浏览过某过个广告的次数,但是一个广告可以投放到多个页面,所以一个人可以在不同页面浏览相同的广告,这在输入数据里就会被当做多笔输入;下面是这个API的输入输出定义
- 输入:userid(用户身份),adid(广告标示),adflag(广告投放位置),pv(该人已在此广告位置浏览了几次,其实多半是刷新)
- 输出:累加输入的广告标示在某广告位置的PV,UV
function statAd(userid, adflag, adid, pv, __ARGVEND__, v, newpv, newuv) { item = adid" "adflag if(item in LIST) { split(LIST[item],v," ") v[1] += pv if(!(item" "userid in ITEM_USERS)) { v[2] += 1 } LIST[item] = v[1]" "v[2] } else { newpv = 1 newuv = 1 LIST[item] = newpv" "newuv ITEM_USERS[item" "userid] } } { userid = $1 adflag = $2 adid = $3 pv = $4 statAd(userid,adflag,adid,pv) }
awk的程序还是比较像javascript的,语法上应该不需要太多说明,需要说明的一定是$1,$2这样的符号,其实这是调用该程序的输入,可以理解为命令行调用时在shell里写入的参数。写好之后觉得很高兴,代码看起来很整洁,很清晰,觉得没有什么问题,就放上线了(是的,我们没有测试)但是呢,觉得自己应该对自己的代码负责,还是应该看看有没有问题
于是造了一个玩具assert函数(awk里没有这样的库函数)
function assert(testConditon, message,__ARGVEND__) { if(! testConditon) { print message exit -1 } }
之后构造测试用例,调用功能模块的API,并将它的输入和预想的结果相比较,这是测试的基本思路,应该不用多说
@include lib/assert.awk @include statapi.awk { x[1] a[1,"userid"] = 100 a[1,"adflag"] = "XX_YY_ZZ_11" a[1,"adid"] = 200 a[1,"pv"] = 12 x[2] a[2,"userid"] = 200 a[2,"adflag"] = "XX_YY_ZZ_11" a[2,"adid"] = 200 a[2,"pv"] = 14 for(i in x) { statAd(a[i,"userid"],a[i,"adflag"],a[i,"adid"],a[i,"pv"]) } for(i in LIST) { print i" "LIST[i] } assert("200 XX_YY_ZZ_11" in LIST,"assertion faild:erro1") assert(LIST["200 XX_YY_ZZ_11"] == "26 2","assertion faild:error2") }
assert函数在assert.awk中,statAd函数在statapi.awk中,测试用例的代码首先把他们include进来,之后开始构造测试数据,一共造了两笔广告浏览记录,表示的是两个用户在同一个地方浏览了相同的广告(多次),应该说是最最最基本的测试用例了,我预想的结果是pv26,uv2,那么输出结果就是"26 2"(这是程序特殊的保存数据的方式造成的,测试应该适应程序的表达方式)但是结果,没有通过!提示assertion faild:error2
因为之前我心里已经认定程序是没有问题的,所以这次这个测试也只是锦上添花的验证性程序(就是想证明自己是对的)没想到程序一下子就告诉我,我挂了,心里的郁闷就别提了,稀里哗啦,开始在功能模块上追加日志:
function statAd(userid, adflag, adid, pv, __ARGVEND__, v, newpv, newuv) { item = adid" "adflag print "debug 1 : "item if(item in LIST) { print"debug 2 : "item" in LIST" split(LIST[item],v," ") v[1] += pv if(!(item" "userid in ITEM_USERS)) { v[2] += 1 } LIST[item] = v[1]" "v[2] print"debug 2.1 : "item" is "LIST[item] } else { print"debug 3 : "item" not in LIST" newpv = 1 newuv = 1 LIST[item] = newpv" "newuv ITEM_USERS[item" "userid] print"debug 3.1 : "item" is "LIST[item] } }
再次执行,输出是
debug 1 : 200 XX_YY_ZZ_11 debug 3 : 200 XX_YY_ZZ_11 not in LIST debug 3.1 : 200 XX_YY_ZZ_11 is 1 1 debug 1 : 200 XX_YY_ZZ_11 debug 2 : 200 XX_YY_ZZ_11 in LIST debug 2.1 : 200 XX_YY_ZZ_11 is 15 2 200 XX_YY_ZZ_11 15 2 assertion faild:error2
一下子发现问题,输出的debug3.1说pv,uv都是1,但是,这里的数据是经过初步统计的,我输入的也不是1,再看代码,原来我就写死了pv,uv都是1,修改代码
function statAd(userid, adflag, adid, pv, __ARGVEND__, v, newpv, newuv) { item = adid" "adflag print "debug 1 : "item if(item in LIST) { print"debug 2 : "item" in LIST" split(LIST[item],v," ") v[1] += pv if(!(item" "userid in ITEM_USERS)) { v[2] += 1 } LIST[item] = v[1]" "v[2] print"debug 2.1 : "item" is "LIST[item] } else { print"debug 3 : "item" not in LIST" newpv = pv #造成bug的地方,修改之 newuv = 1 LIST[item] = newpv" "newuv ITEM_USERS[item" "userid] print"debug 3.1 : "item" is "LIST[item] } }
再运行,输出:
debug 1 : 200 XX_YY_ZZ_11 debug 3 : 200 XX_YY_ZZ_11 not in LIST debug 3.1 : 200 XX_YY_ZZ_11 is 12 1 debug 1 : 200 XX_YY_ZZ_11 debug 2 : 200 XX_YY_ZZ_11 in LIST debug 2.1 : 200 XX_YY_ZZ_11 is 26 2 200 XX_YY_ZZ_11 26 2
好了,这次通过测试用例了,那程序是不是就没有问题了呢,(好吧,我感觉是)但是这个测试用例证明的只是“在不同用户访问同一个位置同一个广告的”情况下是没有问题的。其他情况还是需要进行测试,才能说是没有问题的,我这种资质的人只能通过这样的办法给自己树立信心,我不知道牛人们是不是应该很少犯我犯的错误呢?如果他们能很少犯错,到底是天生呢还是后天锻炼,如果是后天锻炼是通过什么办法锻炼出来的呢,求解
还有,awk看样子很需要log4awk这样的库啊!!!
不幸的,我通过review又发现一个bug(这次倒不是通过测试用例发现)该bug的现象时某些时候同一个用户,对于同一个位置的广告多次访问,他的UV会多累加,这个BUG出现的前提是:1。广告以及他的某个位置已被记录(之后再提及的时候不再强调这个广告和广告的位置都是和这个被记录的广告是相同的了) 2。访问这个广告的用户非让这个广告被记录的用户 3.这个用户会多次访问这个广告(理论上初步统计的程序会把同一个用户对广告A在位置Y上的多次访问捏成一条记录,但是如果出现这情况,程序是不是应该也能容错呢?)
function statAd(userid, adflag, adid, pv, __ARGVEND__, v, newpv, newuv) { item = adid" "adflag print "debug 1 : "item if(item in LIST) { print"debug 2 : "item" in LIST" split(LIST[item],v," ") v[1] += pv if(!(item" "userid in ITEM_USERS)) { v[2] += 1 ITEM_USERS[item" "userid] #其他用户访问已记录的广告,这次访问需要被记录 } LIST[item] = v[1]" "v[2] print"debug 2.1 : "item" is "LIST[item] } else { print"debug 3 : "item" not in LIST" newpv = pv newuv = 1 LIST[item] = newpv" "newuv ITEM_USERS[item" "userid] pdflag -
来源:https://www.cnblogs.com/code-style/archive/2013/05/22/3093511.html