Testing lua script with busted
我正在尝试测试我们的Freeswitch lua脚本是否崩溃,并且遇到了麻烦。要点是,我需要能够监视以下类似的代码
1 2 | local req_host = session:getVariable('sip_req_host') session:setVariable('curl_timeout', 0) |
但是我似乎无法弄清楚如何构建应将_G.session设置为的对象。我可以找到的关于如何使用破获的最好/唯一的好例子是在https://github.com/chris-allnutt/unit-tested-corona/blob/master/mocks/button.lua,但它似乎使用了相同的方法用于构建被破坏的文档执行的模拟对象的简单语法。
1 2 3 4 5 | local button = { x = 0, y = 0, addEventListener = function() end } |
我可以看到这对于不需要返回任何内容的简单函数将如何工作,但是我需要能够使用getVariable和setVariable函数在会话对象中获取和设置变量。我的简单模拟对象如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Session = {} Session.__index = Session function Session.create(params) local session = {} setmetatable(session, Session) session.params = params return session end function Session:getVariable(key) return self.params[key] end function Session:setVariable(key, val) self.params[key] = val end function Session:execute(cmd, code) end |
,测试如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | require"busted" require("test_utils") describe("Test voip lua script", function() it('Test webrtc bad domain', function() domain = 'rtc.baddomain.com'; session_params = {['sip_req_host'] = domain, ['sip_req_user'] = 'TEST-WebRTC-Client', ["sip_from_user"] = 'testwebrtc_p_12345', ['sip_call_id'] = 'test@call_id', ['sip_authorized'] = 'false'} exec_str = 'sofia_contact TEST-WebRTC-Client@'..domain; api_params = {[exec_str] = 'error/user_not_registered'} _G.session = mock(Session.create(session_params), 'execute') _G.api = API.create(api_params) _G.freeswitch = Freeswitch.create() dofile("tested_script.lua") assert.spy(_G.session.execute).called_with("respond","407") end) end) |
我最终遇到以下异常。
/usr/local/share/lua/5.2/luassert/spy.lua:78:尝试为函数值建立索引
luassert(已破坏的库的依赖项)在以下if语句中抛出此异常
1 2 3 4 5 6 7 | 77:local function called_with(state, arguments) 78: if rawget(state,"payload") and rawget(state,"payload").called_with then 79: return state.payload:called_with(arguments) 80: else 81: error("'called_with' must be chained after 'spy(aspy)'") 82: end 83:end |
我对lua还是很陌生,所以似乎我只是缺少了该语言的一些明显部分,但是任何帮助或指针都将不胜感激。
因此,经过一天调试后,我发现的答案是,是的,您确实需要使用表作为调用模拟对象。但是,由于在构建具有可调用参数的对象时lua是一种非常宽容的语言,因此它仍然可以正常工作。由于与该问题无关的原因,我围绕该对象构建了package器,但是您可以在下面看到我最终所做的工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function SessionConstructor.create(params) local session_constructor = {} setmetatable(session_constructor, SessionConstructor) session_constructor.session = {} session_constructor.session.params = params session_constructor.session.getVariable = function(self,key) return self.params[key] end session_constructor.session.setVariable = function(self, key, val) self.params[key] = val end session_constructor.session.execute = function(self, cmd, code) end return session_constructor end function SessionConstructor:construct() return self.session end |
一个重要的警告,因为您必须将self传递到将使用lua的":"语法调用的函数,因此监视间谍函数的方法的确发生了变化,如下面的测试文件所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | require"busted" require"test_utils" describe("Test voip lua script", function() it('Test webrtc bad domain', function() domain = 'rtc.baddomain.com'; session_params = {['sip_req_host'] = domain, ['sip_req_user'] = 'TEST-WebRTC-Client', ["sip_from_user"] = 'testwebrtc_p_12345', ['sip_call_id'] = 'test@call_id', ['sip_authorized'] = 'false'} local sess_con = SessionConstructor.create(session_params) exec_str = 'sofia_contact TEST-WebRTC-Client@'..domain; local api_con = APIConstructor.create() api_con:expect_exec(exec_str, 'error/user_not_registered') _G.session = mock(sess_con:construct()) _G.api = mock(api_con:construct()) _G.freeswitch = create_freeswitch() dofile("tested_script.lua") assert.spy(session.execute).was.called_with(session,"respond","407") assert.spy(session.execute).was_not.called_with("respond","407") --This is unfortunate end) end) |
FreeSWITCH中的
mod_lua使用了稍微定制的Lua解释器,并且您似乎使用了安装在主机上的其他Lua解释器。我想他们不会轻易合作。
我对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | busted = require 'busted.core'() local environment = require 'busted.environment'(busted.context) function unpack(t, i) i = i or 1 if t[i] ~= nil then return t[i], unpack(t, i + 1) end end busted.getTrace = function(element, level, msg) level = level or 3 local info = debug.getinfo(level, 'Sl') info.traceback = debug.traceback('', level) info.message = msg if msg ~= nil then freeswitch.consoleLog("NOTICE", msg) end local file = busted.getFile(element) return file.getTrace(file.name, info) end busted.safe = function(descriptor, run, element, setenv) if setenv and (type(run) == 'function' or getmetatable(run).__call) then -- prioritize __call if it exists, like in files environment.wrap(getmetatable(run).__call or run) end busted.context.push(element) local trace, message local ret = { xpcall(run, function(msg) message = busted.rewriteMessage(element, msg) freeswitch.consoleLog("ERR", message) trace = busted.getTrace(element, 3, msg) end) } if not ret[1] then busted.publish({ 'error', descriptor }, element, busted.context.parent(element), message, trace) end busted.context.pop() return unpack(ret) end require 'busted.init'(busted) local checkTag = function(name, tag, modifier) local found = name:find('#' .. tag) return (modifier == (found ~= nil)) end local checkTags = function(name) for i, tag in pairs(tags) do if not checkTag(name, tag, true) then return nil, false end end for i, tag in pairs(excludeTags) do if not checkTag(name, tag, false) then return nil, false end end return nil, true end local getTrace = function(filename, info) local index = info.traceback:find('\ %s*%[C]') info.traceback = info.traceback:sub(1, index) return info, false end local file = setmetatable({ getTrace = getTrace }, { __call = loadfile("/path/scripts/main_spec.lua") }) busted.executors.file("main_spec.lua", file) local failures = 0 local errors = 0 busted.subscribe({ 'error' }, function() errors = errors + 1 end) busted.subscribe({ 'test', 'end' }, function(element, parent, status) if status == 'failure' then failures = failures + 1 end end) busted.publish({ 'suite', 'start' }) busted.execute() busted.publish({ 'suite', 'end' }) freeswitch.consoleLog("NOTICE","Failures:" .. failures) freeswitch.consoleLog("NOTICE","Errors:" .. errors) |
该脚本仅对一个文件(
您可以通过Freeswitch控制台中的
1 2 | fs_cli luarun /path/to/runner.lua |
您将在此处获得输出。