我试图在Lua中使用Busted(出于业务原因,我没有写,现在也不允许重构)对单元代码进行单元测试,并且在该类的模块或依赖注入中没有概念。因此,我想用模拟记录器替换文件顶部即local log = require("path.to.module.logger"):new()
所需的一些模块,该记录器是我用来跟踪方法被调用的次数的,例如logger:trace()
就像Java中Mockito中的times()
一样。在Java中,可以为此使用Reflection.Utils。 Lua中有什么等效功能可以帮助使此不可测试的代码可测试?
我已经尝试使用以下示例创建具有相同变量名log
的全局变量,并将其设置为与我的模拟相同:https://www.lua.org/pil/14.2.html
本地_M = {}
本地日志= require(“ path.to.module.logger”):new()
...
函数_M.init(...) log:trace(“ debug”)#我希望此日志实例不是上面的实例,而是我在运行时注入模块的实例 结束
答案 0 :(得分:0)
在Lua中,“ Reflection”并不是真正的东西,不是Java的意思。作为使用Duck Typing的语言,所有内容都是非常开放的。 Lua只有一个数据结构:一个表。 Lua中的一切来自表。模块只是由require
加载的块返回的表。
可以通过元表隐藏表后面的内容和数据结构,这些表可用于防止正常的迭代过程(pairs
,ipairs
等)访问表中的元素。但是,您始终可以使用getmetatable
来提取元表本身并进行调用;您甚至可以突破用debug.getmetatable
隐藏元表的常规方法。
话虽这么说,因为Lua依赖于Duck Typing,并且因为Lua的API非常开放,所以全面包装每个单独的函数和表是很困难的。
例如,假设您要包装一个模块。这很容易;只需创建一个具有元表的空表,该元表的元方法调用包装的模块方法。这适用于该模块的直接API。
但是,如果其中一个API返回一个需要包装本身的对象,会发生什么情况?您如何分辨专用API对象和常规表之间的区别?同样重要的是,如果您可以成功地确定需要包装哪些返回值,该如何做?毕竟,如果它们将包装器表中的一个传递给包装器API函数,则现在需要解开该表,以便将包装后的表传递给要包装的实际函数。
答案 1 :(得分:0)
实际上我今天早上能从同事那里找到答案。正如Nicol Bolas在他的回答中所建议的那样,“反射”实际上是不可能的,但是,从lua文档(http://lua-users.org/wiki/ModulesTutorial)中,我们了解到:
Lua caches modules in the package.loaded table.
这意味着我们可以在中断的测试中覆盖package.loaded
表,并且基本上在运行时替换紧密耦合的代码中的依赖项(就像在Java中通过依赖项注入在Mockito中进行模拟)。例如:
package.loaded["path.to.module.logger"] = my_logger
将使用path.to.module.logger
全局替换依赖项my_logger
,前提是它遵守相同的合同。
答案 2 :(得分:0)
我将为记录器编写模拟文件,并将其设置为与原始记录器相同的路径,但位于不同的目录根目录下。然后对于测试,在LUA_PATH的开头添加带有模拟的文件夹
示例: /tmp/a/package/logger.lua:
local _M = {}
_M.log = function()
print "Original logger"
end
return _M
/tmp/b/package/logger.lua:
local _M = {}
_M.log = function()
print "Mocked logger"
end
return _M
和测试/tmp/test/logger_spec.lua:
describe("Test suite", function()
it("Testing the mock", function ()
local log = require("package.logger")
log.log()
end)
end)
如果将LUA_PATH设置为使用original:
export LUA_PATH="/tmp/a/?.lua;;"
并拨打电话:
busted logger_spec.lua
Original logger
●
1 success / 0 failures / 0 errors / 0 pending : 0.000527 seconds
现在将LUA_PATH指向您的模拟:
export LUA_PATH="/tmp/b/?.lua;;"
然后再次拨打电话
busted logger_spec.lua
Mocked logger
●
1 success / 0 failures / 0 errors / 0 pending : 0.000519 seconds