Pergunta

Eu sou um novato Lua. Estou unidade testar Lua 5.1 código usando LUNITY e LeMock .

A minha turma é StorageManager. Estou unidade testar seu método load (), que carrega os arquivos do disco. Eu não quero que minha unidade testes dependem dos arquivos reais no disco real para testar isso.

Então, eu estou tentando injetar o I / O de dependência com um objeto de simulação e verificar o comportamento desse objeto durante o meu teste. Eu não consigo descobrir como usar o objeto de E / S com uma sintaxe que funciona quando chamado por tanto o meu teste de unidade com base em simulação e o "código real".

Como posso alterar o código (o método load (), de preferência) para que ele irá fazer o seu trabalho quando chamado a partir de qualquer teste de unidade (um sem o simulado é temporário até que eu obter este descobriu - se assemelha a código que irá mais tarde, na verdade, chamar o método em teste)?

Nota 1:. Se você executar esses testes, lembre-se que o teste "sem falsa" espera um arquivo no disco cujo nome corresponde VALID_FILENAME

Nota 2: Pensei em usar try / catch-como comportamento para executar uma linha de pcall ou o outro (ver linhas storageManager.lua 11 e 12). Assumindo que é mesmo possível, ela se sente como um hack, e armadilhas erros que eu poderia mais tarde Quer jogadas (de carga ()). Por favor expor sobre esta opção se você não vê nenhuma alternativa.

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

Editar:

Essas classes passar ambos os testes. Muitos graças ao 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
Foi útil?

Solução

Eu acho que você está fazendo o problema mais difícil do que tem que ser.

Assumindo que o módulo storageManager.lua não em si é localizar o módulo io, então tudo que você precisa fazer é substituir o io global com o seu objeto fictício durante a execução do teste.

Se o módulo faz localizar o objeto io para o desempenho, então você precisa injetar o novo valor de io antes de carregar o módulo. Isso pode significar que você precisa para fazer a chamada para parte require da configuração do caso de teste (e uma limpeza correspondente que remove todos os traços do módulo de package.loaded e _G) para que ele possa ser ridicularizado diferente em diferentes casos de teste. WinImage

Editar:

Ao localizar um módulo para o desempenho Quero dizer a linguagem Lua de copiar os métodos do módulo em variáveis ??locais no espaço o nome do módulo. Por exemplo:

-- 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

Se você fizer isso, as referências à io módulos de ações e math são feitas no momento em que require "somemodule" é executado. Substituir um desses módulos após a chamada para require() com uma versão zombou não será eficaz.

Para zombar efetivamente um módulo que é usado com este idioma, você teria que ter o objeto fictício no lugar antes a chamada para require().

Aqui é um como eu iria sobre a substituição do objeto io para a duração da chamada em um caso de teste:

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

I podem não ser restaurar o objeto real, exatamente no momento certo, e isso não foi testado, mas deve apontar na direção certa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top