有几个小问题会阻止您的代码工作:首先,您不能通过http
设置同名的全局变量来覆盖本地。局部变量总是会影响全局变量。
其次,仍会调用 require ,如果您local
在测试代码中删除了 ,它仍然会覆盖当时保存在全局http
变量中的任何内容。
您需要的是一种在调用时require
加载resty.fake_http
模块的方法require "resty.http"
。我能想到的方法有以下三种:
1. 预加载模块
该require
函数使用这两个表package.loaded
来package.preload
控制何时以及如何加载模块(详情请点击此处)。当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
目录添加到路径来执行此操作。您需要做的就是将您的假模块命名为与原始模块相同的名称,它将自动加载。例如测试_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
功能,那么这可以帮助您应对未来更复杂的情况。