Lua I/O 依赖注入
2009-6-21 17:52:10
收藏:0
阅读:309
评论:1
我是一个Lua新手。我正在使用Lunity和LeMock对Lua 5.1代码进行单元测试。
我的类是StorageManager。我正在对其load()方法进行单元测试,该方法从磁盘加载文件。我不希望我的单元测试依赖于实际磁盘上的实际文件来测试。
因此,我试图使用模拟对象注入I / O依赖项,并验证该对象在我的测试期间的行为。我无法弄清楚如何使用I / O对象以在我的基于模拟的单元测试和“真实代码”调用时均使用的语法。
我该如何更改代码(尽可能是load()方法),以便在从任一单元测试调用时执行其工作(没有模拟的临时测试,直到我弄清楚为止 - 它类似于稍后实际调用要测试的方法的代码)?
注意1:如果运行这些测试,请记住,“没有模拟”测试期望在磁盘上有一个文件,其文件名与VALID_FILENAME匹配。
注意2:我考虑过使用pcall的try / catch-like行为来执行一行或另一行(参见storageManager.lua第11和12行)。假设这是可能的,它感觉像一个黑客,并且它捕获我以后可能想要抛出的错误(从load())中。如果您看不到替代方案,请详细解释此选项。
require "StorageManager"
require "lunity"
require "lemock"
module("storageManager", package.seeall, lunity)
VALID_FILENAME = "storageManagerTest.dat"
function setup()
mc = lemock.controller()
end
function test_load_reads_file_properly()
io_mock = mc:mock()
file_handle_mock = mc:mock()
io_mock:open(VALID_FILENAME, "r");mc:returns(file_handle_mock)
file_handle_mock:read("*all")
file_handle_mock:close()
mc:replay()
storageManager = StorageManager:new{ io = io_mock }
storageManager:load(VALID_FILENAME)
mc:verify()
end
function test_load_reads_file_properly_without_mock()
storageManager = StorageManager:new()
storageManager:load(VALID_FILENAME)
end
runTests{useANSI = false}
StorageManager = {}
function StorageManager.new (self,init)
init = init or { io=io } -- I/O dependency injection attempt
setmetatable(init,self)
self.__index = self
return init
end
function StorageManager:load(filename)
file_handle = self['io'].open(self['io'], filename, "r") -- works w/ mock
-- file_handle = io.open(filename, "r") -- works w/o mock
result = file_handle:read("*all")
file_handle:close()
return result
end
这些类通过了两个测试。非常感谢RBerteig。
require "admin.StorageManager"
require "tests.lunity"
require "lib.lemock"
module("storageManager", package.seeall, lunity)
VALID_FILENAME = "storageManagerTest.dat"
function setup()
mc = lemock.controller()
end
function test_load_reads_file_properly()
io_mock = mc:mock()
file_handle_mock = mc:mock()
io_mock.open(VALID_FILENAME, "r");mc:returns(file_handle_mock)
file_handle_mock:read("*all")
file_handle_mock:close()
mc:replay()
local saved_io = _G.io
_G.io = io_mock
package.loaded.io = io_mock
storageManager = StorageManager:new()
storageManager:load(VALID_FILENAME)
_G.io = saved_io
package.loaded.io = saved_io
mc:verify()
end
function test_load_reads_file_properly_without_mock()
storageManager = StorageManager:new()
storageManager:load(VALID_FILENAME)
end
runTests{useANSI = false}
StorageManager = {}
function StorageManager.new (self,init)
init = init or {}
setmetatable(init,self)
self.__index = self
return init
end
function StorageManager:load(filename)
file_handle = io.open(filename, "r")
result = file_handle:read("*all")
file_handle:close()
return result
end
原文链接 https://stackoverflow.com/questions/1021125
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我认为您让问题变得比必须的更困难了。
假设模块
storageManager.lua
没有本地化io
模块本身,那么您只需要在运行测试时用您的模拟对象替换全局的io
。如果模块对
io
对象进行了本地化以提高性能,则需要在加载模块之前注入新的io
值。这可能意味着您需要在测试用例设置中进行对require
的调用(以及配套的清理,从package.loaded
和_G
中删除模块的所有痕迹),以便在不同的测试用例中进行不同的模拟。WinImage
编辑:
通过本地化模块来提高性能,我指的是 Lua 的惯用法,即将模块的方法复制到模块名称空间中的局部变量中。例如:
- somemodule.lua require "io" require "math" -- 复制 io 和 math 到本地变量 local io, math = io, math -- 开始模块本身,注意没有使用 package.seeall,因此全局变量 -- 在此时之后不可见 module(...) function doMathAndIo() -- 从这里开始做一些有趣的事情 end
如果您这样做,对库存模块
io
和math
的引用是在执行require "somemodule"
时进行的。在调用require()
之后将其中任何一个模块替换为模拟版本将是无效的。要有效地模拟使用此惯用法的模块,您必须在调用
require()
之前放置模拟对象。以下是我如何在测试用例中替换 io 对象的过程:
function test_load_reads_file_properly() io_mock = mc:mock() file_handle_mock = mc:mock() io_mock:open(VALID_FILENAME, "r");mc:returns(file_handle_mock) file_handle_mock:read("*all") file_handle_mock:close() mc:replay() local saved_io = _G.io _G.io = io_mock package.loaded.io = io_mock storageManager = StorageManager:new{ } storageManager:load(VALID_FILENAME) _G.io = saved_io package.loaded.io = saved_io mc:verify() end
我可能没有在恰当的时刻恢复真实对象,并且这是未经测试的,但它应该能指引您正确的方向。