使用 Busted 对 Lua 代码进行单元测试时模拟本地导入

won*_*erv 6 lua unit-testing lua-busted

我对 Lua 很陌生,我正在尝试测试我在 Nginx 服务器上运行的脚本。我被推荐 Busted 但我似乎无法弄清楚如何模拟一些本地进口。

Lua 代码导入以下内容:

local http = require "resty.http"
Run Code Online (Sandbox Code Playgroud)

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

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

_G.http = require('resty.fake_http')
local app = require('app')
Run Code Online (Sandbox Code Playgroud)

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

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

suite spec/app_spec.lua
files/app.lua:3: module 'resty.http' not found:No LuaRocks module found for resty.http
Run Code Online (Sandbox Code Playgroud)

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

sol*_*sol 8

有几个小问题会阻止您的代码工作:首先,您无法http通过设置同名的全局变量来覆盖本地变量。局部变量将始终隐藏全局变量。

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

您需要的是一种在调用时require加载模块的方法。我能想到的方法有以下三种:resty.fake_httprequire "resty.http"

1. 预加载模块

require函数使用两个表package.loadedpackage.preload控制何时以及如何加载模块(详细信息请参见此处)。require调用时,它首先检查是否package.loaded[module]已设置,如果已设置,则返回该值。

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

package.loaded["resty.http"] = require "resty.fake_http"
local app = require('app')
Run Code Online (Sandbox Code Playgroud)

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

package.preload["resty.http"] = function ()
  return require("resty.fake_http")
end
local app = require('app')
Run Code Online (Sandbox Code Playgroud)

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

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

package.path = "files/?.lua;spec/?.lua;" .. package.path
local app = require('app')
Run Code Online (Sandbox Code Playgroud)

在测试的代码中,它会自动拾取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')
Run Code Online (Sandbox Code Playgroud)

第二种方法是最容易实现和理解的,但第一种方法更干净、更通用。如果您能抽出 30 分钟时间阅读链接的文档并了解其require功能,这可以帮助您应对未来更复杂的情况。