Я новичок Lua. Я тестирую код Lua 5.1 с использованием Lunity и LeMock .
Мой класс - StorageManager. Я тестирую его метод load (), который загружает файлы с диска. Я не хочу, чтобы мои модульные тесты зависели от реальных файлов на реальном диске, чтобы это проверить.
Итак, я пытаюсь внедрить зависимость ввода-вывода с помощью фиктивного объекта и проверить поведение этого объекта во время теста. Я не могу понять, как использовать объект ввода-вывода с синтаксисом, который работает, когда он вызывается как моим модульным тестом, основанным на имитации, так и «реальным кодом».
Как я могу изменить код (предпочтительно метод load ()), чтобы он выполнял свою работу при вызове из любого модульного теста (тот, у которого нет макета, является временным, пока я не выясню это - он похож код, который позже будет вызывать тестируемый метод)?
Примечание 1. Если вы запустите эти тесты, помните, что тест «без макета» ожидает файл на диске, имя файла которого совпадает с VALID_FILENAME.
Примечание 2: Я думал об использовании pcall-подобного поведения try / catch для выполнения одной или другой строки (см. StorageManager.lua, строки 11 и 12). Предполагая, что это даже возможно, это похоже на хак, и это ловит ошибки, которые я мог бы позже хотеть выбросить (вне нагрузки ()). Пожалуйста, разъясните эту опцию, если вы не видите альтернативы.
test_storageManager.lua:
1 require "StorageManager"
2 require "lunity"
3 require "lemock"
4 module("storageManager", package.seeall, lunity)
5
6 VALID_FILENAME = "storageManagerTest.dat"
7
8 function setup()
9 mc = lemock.controller()
10 end
11
12 function test_load_reads_file_properly()
13 io_mock = mc:mock()
14 file_handle_mock = mc:mock()
15 io_mock:open(VALID_FILENAME, "r");mc:returns(file_handle_mock)
16 file_handle_mock:read("*all")
17 file_handle_mock:close()
18 mc:replay()
19 storageManager = StorageManager:new{ io = io_mock }
20 storageManager:load(VALID_FILENAME)
21 mc:verify()
22 end
23
24 function test_load_reads_file_properly_without_mock()
25 storageManager = StorageManager:new()
26 storageManager:load(VALID_FILENAME)
27 end
28
29 runTests{useANSI = false}
storageManager.lua:
1 StorageManager = {}
2
3 function StorageManager.new (self,init)
4 init = init or { io=io } -- I/O dependency injection attempt
5 setmetatable(init,self)
6 self.__index = self
7 return init
8 end
9
10 function StorageManager:load(filename)
11 file_handle = self['io'].open(self['io'], filename, "r") -- works w/ mock
12 -- file_handle = io.open(filename, "r") -- works w/o mock
13 result = file_handle:read("*all")
14 file_handle:close()
15 return result
16 end
Edit:
Эти классы проходят оба теста. Большое спасибо RBerteig.
test_storageManager.lua
1 require "admin.StorageManager"
2 require "tests.lunity"
3 require "lib.lemock"
4 module("storageManager", package.seeall, lunity)
5
6 VALID_FILENAME = "storageManagerTest.dat"
7
8 function setup()
9 mc = lemock.controller()
10 end
11
12 function test_load_reads_file_properly()
13 io_mock = mc:mock()
14 file_handle_mock = mc:mock()
15 io_mock.open(VALID_FILENAME, "r");mc:returns(file_handle_mock)
16 file_handle_mock:read("*all")
17 file_handle_mock:close()
18 mc:replay()
19 local saved_io = _G.io
20 _G.io = io_mock
21 package.loaded.io = io_mock
22 storageManager = StorageManager:new()
23 storageManager:load(VALID_FILENAME)
24 _G.io = saved_io
25 package.loaded.io = saved_io
26 mc:verify()
27 end
28
29 function test_load_reads_file_properly_without_mock()
30 storageManager = StorageManager:new()
31 storageManager:load(VALID_FILENAME)
32 end
33
34 runTests{useANSI = false}
storageManager.lua
1 StorageManager = {}
2
3 function StorageManager.new (self,init)
4 init = init or {}
5 setmetatable(init,self)
6 self.__index = self
7 return init
8 end
9
10 function StorageManager:load(filename)
11 file_handle = io.open(filename, "r")
12 result = file_handle:read("*all")
13 file_handle:close()
14 return result
15 end