Je suis un novice Lua. Je suis unité testant le code Lua 5.1 en utilisant Lunity et LeMock.Lua I/O injection de dépendance
Ma classe est StorageManager. Je suis unité de tester sa méthode load(), qui charge les fichiers à partir du disque. Je ne veux pas que mes tests unitaires dépendent de fichiers réels sur le disque réel pour le tester. Donc, j'essaie d'injecter la dépendance d'E/S avec un objet simulé et de vérifier le comportement de cet objet pendant mon test. Je n'arrive pas à comprendre comment utiliser l'objet d'E/S avec une syntaxe qui fonctionne lorsqu'elle est appelée à la fois par mon test unitaire basé sur des simulacres et par le "vrai code". Comment puis-je changer le code (la méthode load(), de préférence) afin qu'il fasse son travail lorsqu'il est appelé à partir de l'un des tests unitaires (celui sans le simulacre est temporaire jusqu'à ce que je compris cela - il ressemble le code qui appellera plus tard la méthode sous test)?
Remarque1: Si vous exécutez ces tests, rappelez-vous que le test "sans simulation" attend un fichier sur le disque dont le nom de fichier correspond à VALID_FILENAME.
Note2: J'ai pensé utiliser le comportement try/catch de pcall pour exécuter une ligne ou l'autre (voir storageManager.lua lignes 11 & 12). En supposant que c'est même possible, cela ressemble à un hack, et il piège les erreurs que je pourrais éventuellement vouloir lancer (out of load()). S'il vous plaît exposer sur cette option si vous ne voyez pas d'alternative.
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:
Ces classes passent deux tests. Merci beaucoup au 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
Je ne veux pas dire (ou savoir comment) «localiser l'objet io pour la performance», mais je veux «remplacer l'io global par [mon] objet fantôme pendant l'exécution du test». Je pensais que je faisais ça sur storageManager.lua: 4? Comment peut-on "remplacer le io global"? Pouvez-vous fournir (ou me diriger vers) un exemple de code? – lance
Votre édition m'a donné ce dont j'avais besoin. J'ai modifié mon code modifié dans la question d'origine. Merci beaucoup. – lance