【问题标题】:Testing lua script with busted用 busted 测试 lua 脚本
【发布时间】:2014-04-30 01:11:03
【问题描述】:

我正在尝试使用 busted 测试我们的 Freeswitch lua 脚本,但遇到了障碍。它的要点是我需要能够监视如下代码

local req_host = session:getVariable('sip_req_host')
session:setVariable('curl_timeout', 0)

但我似乎无法弄清楚如何构建我应该将 _G.session 设置为的对象。我能找到的关于如何使用 busted 的最佳/唯一好的示例是 https://github.com/chris-allnutt/unit-tested-corona/blob/master/mocks/button.lua,但它似乎使用与 busted 文档相同的简单语法来构建模拟对象。

local button = {
  x = 0,
  y = 0,
  addEventListener = function() end
}

我可以看到这对于不需要返回任何内容但我需要能够使用 getVariable 和 setVariable 函数在会话对象中获取和设置变量的简单函数是如何工作的。我的简单模拟对象如下:

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

测试如下

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 语句中

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 很陌生,所以我似乎只是遗漏了该语言的一些明显部分,但任何帮助或指针将不胜感激。

【问题讨论】:

标签: unit-testing lua freeswitch lua-busted


【解决方案1】:

所以我在调试了一天后发现的答案是,是的,您确实需要使用表作为您调用模拟的对象。然而,由于 lua 是一种非常宽容的语言,因此在构建具有可调用参数的对象时,它仍然可以正常工作。由于与此问题无关的原因,我围绕对象构建了一个包装器,但您可以在下面看到我最终所做的工作。

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 的“:”语法调用的函数,所以监视调用函数的方法确实发生了变化,如下面的测试文件所示。

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)

【讨论】:

    【解决方案2】:

    FreeSWITCH 中的 mod_lua 使用了稍微定制的 Lua 解释器,而您似乎使用了安装在主机上的不同 Lua 解释器。我想他们不会轻易合作。

    【讨论】:

      【解决方案3】:

      我对@9​​87654321@ bin 脚本做了一些逆向工程,得到了下面的脚本(姑且称之为runner.lua):

      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('\n%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)
      

      该脚本仅适用于一个文件,/path/scripts/main_spec.lua,但仍然可用。 您可以使用此 runner.lua 脚本执行的操作是从 Freeswitch 控制台使用 luarun 运行它:

      fs_cli
      luarun /path/to/runner.lua
      

      你会在那里得到输出。

      【讨论】:

        猜你喜欢
        • 2022-10-20
        • 2018-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-23
        • 1970-01-01
        • 1970-01-01
        • 2014-10-12
        相关资源
        最近更新 更多