I'm very new to Lua and I'm trying to test a script I have running with an Nginx server. I've been recommended Busted but I can't seem to figure out how to mock some of the local imports.
The Lua code imports the following:
local http = require "resty.http"
And in the test _spec file, I start off like this:
package.path = "files/?.lua;spec/?.lua;" .. package.path
_G.http = require('resty.fake_http')
local app = require('app')
I created a fake_http.lua file inside spec/resty/http.
But when I run a dummy test, I get the following error:
suite spec/app_spec.lua
files/app.lua:3: module 'resty.http' not found:No LuaRocks module found for resty.http
Any Idea what I'm doing wrong here?
There are a couple of small issues preventing your code from working: First, you cannot override the
httplocal by setting a global variable of the same name. The local will always shadow the global variable.Secondly, require is still being called and if you removed the
localin the test code it would still overwrite whatever was held in the globalhttpvariable at that time.What you need is a way to make
requireload yourresty.fake_httpmodule when called asrequire "resty.http". There are three ways I can think of:1. Preload the module
The
requirefunction uses the two tablespackage.loadedandpackage.preloadto control when and how modules are loaded (details here). Whenrequireis called, it first checks whetherpackage.loaded[module]is set, and if so, returns that value.This is the first opportunity for mocking the module:
Alternatively, if there is no entry in
package.loaded,package.preload[module]is checked for a function that can load the module:2. Change package.path and clobber the module
You are already doing this by adding the
specdirectory to the path. All you need to do is name your fake module the same as the original, and it will be loaded automatically. e.g. test _spec:In the tested code, it will pick up
spec/resty/http.luaautomatically.The difference between these two solutions is that the second one will only require
resty.fake_httpif the tested code actually requires it, while the first one requires it in any case.3. Monkeypatch
requireThis is the ugliest of the three solutions, but it also works fine.
requireis just another global variable, so you can overwrite it as well:The second way is the simplest to do and understand, but the first is even cleaner and more versatile. If you can spare the 30 minutes to read the linked documentation and learn how
requirefunctions, that can help you in more complex cases for the future.