【问题标题】:Mocking local imports when unit-testing Lua code with Busted使用 Busted 对 Lua 代码进行单元测试时模拟本地导入
【发布时间】:2018-07-02 18:15:01
【问题描述】:

我对 Lua 很陌生,我正在尝试测试我在 Nginx 服务器上运行的脚本。有人推荐我 Busted,但我似乎不知道如何模拟一些本地导入。

Lua 代码导入以下内容:

local http = require "resty.http"

在测试 _spec 文件中,我是这样开始的:

package.path = "files/?.lua;spec/?.lua;" .. package.path

_G.http = require('resty.fake_http')
local app = require('app')

我在spec/resty/http 中创建了一个fake_http.lua 文件。

但是当我运行一个虚拟测试时,我得到了以下错误:

suite spec/app_spec.lua
files/app.lua:3: module 'resty.http' not found:No LuaRocks module found for resty.http

知道我在这里做错了什么吗?

【问题讨论】:

    标签: unit-testing lua lua-busted


    【解决方案1】:

    有几个小问题使您的代码无法正常工作: 首先,您不能通过设置同名的全局变量来覆盖 http 局部变量。局部变量总是会影响全局变量。

    其次,require 仍在被调用,如果您删除了测试代码中的 local,它仍然会覆盖当时保存在全局 http 变量中的任何内容。

    您需要一种方法来使require 在调用require "resty.http" 时加载您的resty.fake_http 模块。我可以想到三种方法:

    1。预加载模块

    require 函数使用两个表 package.loadedpackage.preload 来控制何时以及如何加载模块 (details here)。 当调用require 时,它首先检查是否设置了package.loaded[module],如果设置了,则返回该值。

    这是模拟模块的第一个机会:

    package.loaded["resty.http"] = require "resty.fake_http"
    local app = require('app')
    

    或者,如果package.loaded 中没有条目,则检查package.preload[module] 是否有可以加载模块的函数

    package.preload["resty.http"] = function ()
      return require("resty.fake_http")
    end
    local app = require('app')
    

    2。更改 package.path 并破坏模块

    您已经通过将spec 目录添加到路径来执行此操作。您需要做的就是将您的假模块命名为与原始模块相同的名称,它将自动加载。 例如测试规格:

    package.path = "files/?.lua;spec/?.lua;" .. package.path
    local app = require('app')
    

    在测试代码中,它会自动拾取spec/resty/http.lua

    这两种解决方案之间的区别在于,第二种解决方案仅在测试代码实际需要resty.fake_http 时才需要它,而第一种解决方案在任何情况下都需要它。

    3。猴子补丁require

    这是三个解决方案中最难看的一个,但也可以正常工作。 require 只是另一个全局变量,所以你也可以覆盖它:

    local _original_require = require
    function require(modname, ...)
      if modname == "resty.http" then
        -- implement the exception here
        return _original_require("resty.fake_http")
      end
      -- otherewise act as normal
      return _original_require(modname, ...)
    end
    local app = require('app')
    

    第二种方法是最简单易懂的方法,但第一种方法更简洁、更通用。如果您能抽出 30 分钟时间阅读链接的文档并了解 require 的功能,那将有助于您在未来处理更复杂的情况。

    【讨论】:

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