Domanda

Sono una novizia di Lua. Sto testando il codice Lua 5.1 utilizzando Lunity e LeMock .

La mia classe è StorageManager. Sto testando il suo metodo load (), che carica i file dal disco. Non voglio che i miei test unitari dipendano dai file effettivi sul disco effettivo per testarlo.

Quindi, sto cercando di iniettare la dipendenza I / O con un oggetto simulato e verificare il comportamento di quell'oggetto durante il mio test. Non riesco a capire come usare l'oggetto I / O con una sintassi che funziona quando viene chiamato sia dal mio test unit basato su mock sia dal "codice reale".

Come posso cambiare il codice (il metodo load (), preferibilmente) in modo che possa fare il suo lavoro quando viene chiamato da uno dei test unitari (quello senza la simulazione è temporaneo fino a quando non lo capisco - assomiglia al codice che in seguito chiamerà effettivamente il metodo sotto test)?

Nota1: se esegui questi test, ricorda che il " senza finto " test prevede un file su disco il cui nome file corrisponde a VALID_FILENAME.

Nota2: ho pensato di usare il comportamento try / catch-like di pcall per eseguire una riga o l'altra (vedi storageManager.lua righe 11 & amp; 12). Supponendo che sia persino possibile, sembra un trucco e intrappola gli errori che potrei voler lanciare in seguito (senza carico ()). Spiega questa opzione se non vedi 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

Modifica

Queste classi superano entrambi i test. Mille grazie a 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
È stato utile?

Soluzione

Penso che tu stia rendendo il problema più difficile di quanto non debba essere.

Supponendo che il modulo storageManager.lua non stia localizzando il modulo io , quindi tutto ciò che devi fare è sostituire il io globale con il tuo oggetto simulato mentre sei in esecuzione il test.

Se il modulo localizza l'oggetto io per le prestazioni, è necessario iniettare il nuovo valore di io prima di caricare il modulo. Ciò potrebbe significare che è necessario effettuare la chiamata a richiedi parte dell'installazione del test case (e una pulizia corrispondente che rimuove tutte le tracce del modulo da package.loaded e < code> _G ) in modo che possa essere deriso in modo diverso in diversi casi di test. WinImage

Modifica

Localizzando un modulo per prestazioni intendo il linguaggio Lua di copiare i metodi del modulo in variabili locali nello spazio dei nomi del modulo. Ad esempio:

-- somemodule.lua
require "io"
require "math"

-- copy io and math to local variables
local io,math=io,math

-- begin the module itself, note that package.seeall is not used so globals are
-- not visible after this point
module(...)

function doMathAndIo()
    -- does something interesting here
end

In questo caso, i riferimenti ai moduli stock io e math vengono fatti nel momento in cui richiede " somemodule & è eseguito. La sostituzione di uno di questi moduli dopo la chiamata a richiedono () con una versione derisa non sarà efficace.

Per deridere efficacemente un modulo utilizzato con questo idioma, dovresti avere l'oggetto finto in posizione prima la chiamata a richiedono () .

Ecco come farei per sostituire l'oggetto io per la durata della chiamata in un caso di test:

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

Potrei non ripristinare l'oggetto reale esattamente nel momento giusto, e questo non è testato, ma dovrebbe indirizzarti nella giusta direzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top