有几个小问题使您的代码无法正常工作:
首先,您不能通过设置同名的全局变量来覆盖 http 局部变量。局部变量总是会影响全局变量。
其次,require 仍在被调用,如果您删除了测试代码中的 local,它仍然会覆盖当时保存在全局 http 变量中的任何内容。
您需要一种方法来使require 在调用require "resty.http" 时加载您的resty.fake_http 模块。我可以想到三种方法:
1。预加载模块
require 函数使用两个表 package.loaded 和 package.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 的功能,那将有助于您在未来处理更复杂的情况。