Ложный импорт при юнит-тестировании кода Lua с Busted

Я очень новичок в 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')

Я создал 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

Есть идеи, что я здесь делаю не так?

0 ответов

Есть несколько небольших проблем, мешающих работе вашего кода: во-первых, вы не можете переопределить httplocal, установив глобальную переменную с тем же именем. Локальный всегда будет затенять глобальную переменную.

Во-вторых, 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каталог на путь. Все, что вам нужно сделать, это назвать свой поддельный модуль так же, как оригинал, и он будет загружен автоматически. например, test _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 функции, которые могут помочь вам в более сложных случаях в будущем.

Другие вопросы по тегам