[lua][openresty]代码覆盖率检测的解决方式
废话在前什么是代码覆盖率来自百度百科
开发人员为何关注?在我们的开发过程中,经常要用各种方式进行自测,或是各种 xUnit 系列,或是 postman,或是直接curl,在我们的代码交给 QA 同学之前,我们有必要知道自己的自测验过了多少内容,在这种情况,代码覆盖率就是一个重要的衡量指标。 openresty 中的代码覆率解决方案我们如果想得到每一次执行的代码覆率,需要搞定两件事情:
对于第一点,lua的debug库中有一个非常神奇的钩子函数
其中文翻译大体如下:
在这个官方的说明里,lua已经贴心的告诉我们使用方式————配合debug.getinfo,那么debug.getinfo是什么?其实我们在之前讨论错误输出时已经使用过这个方法,其官方文档如下:
这个API的说明中文含义大体如下:
OK,有了这两个方法,我们的思路就变得很清析了:
这里有一个新的问题,就是,我们的汇总是按调用累加还是只针对每一次调用计算,本着实用的立场,我们是需要进行累加的,那么,需要使用ngx.share_dict 来保存汇总信息. 基于以上考虑,封装一个libs/test/hook.lua文件,内容如下: local debug = load "debug" local cjson = load "cjson" local M = {} local mt = { __index = M } local sharekey = 'test_hook' local cachekey = 'test_hook' function M:new() local ins = {} local share = ngx.shared[sharekey] local info,ret = share:get(cachekey) if info then info = cjson.decode(info) else info = {} end ins.info = info setmetatable(ins,mt) return ins end function M:sethook () debug.sethook(function(event,line) local info = debug.getinfo(2) local s = info.short_src local f = info.name local startline = info.linedefined local endline = info.lastlinedefined if string.find(s,"lualib") ~= nil then return end if self.info[s] == nil then self.info[s]={} end if f == nil then return end if self.info[s][f] ==nil then self.info[s][f]={ start = startline,endline=endline,exec = {},activelines = debug.getinfo(2,'L').activelines } end self.info[s][f].exec[tostring(line)]=true end,'l') end function M:save() local share = ngx.shared[sharekey] local ret = share:set(cachekey,cjson.encode(self.info),120000) end function M:delete() local share = ngx.shared[sharekey] local ret = share:delete(cachekey) self.info = {} end function M:get_report() local res = {} for f,v in pairs(self.info) do item = { file=f,funcs={} } for m,i in pairs(v) do local cover = 0 local index = 0 for c,code in pairs(i.activelines) do if i.activelines[c] then index = index + 1 end if i.exec[tostring(c)] or i.exec[c] then cover = cover +1 end end item.funcs[#item.funcs+1] = { name = m,coverage= string.format("%.2f",cover / index*100 ) .."%"} end res[#res+1]=item end return res end return M 这样,我们只需要在content_by_lua的最开始加上: local hook = load "libs.test.hook" local test = hook:new() test:sethook() --other code .. 在最末加上: test:save() 即可统计代码覆盖率。 是的,没错,我们至今只增加了4行业务代码 但是统计了,应该怎么进行输出呢? 加个接口好了:) 因为现在lor用的多,所以,干脆加个lor的路由文件(libs/test/lorapi.lua): local hook = require 'libs.test.hook' local router = lor:Router () local M = {} router:get('/test/coverage/json-report',function(req,res,next) local t = hook:new() res:json(t:get_report()) end) router:get('/test/coverage/txt-report',next) local t = hook:new() local msg = "Report" local rpt = t:get_report() for i,v in pairs(rpt) do msg =msg.."rn"..v.file for j,f in pairs(v.funcs) do msg = msg .."rnt function name:" .. f.name .."tcoverage:"..f.coverage end end msg =msg .."rnEnd" res:send(msg) end) return router 这样,在我们的lor路由文件里加个requre,加个use,两行改动,而且是增加!!就达到我们的需求,检查代码的覆盖率. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |