私はLuaの初心者です。私はLunityとLeMockを使用してユニットテストのLua 5.1のコードです。LuaのI/Oの依存性注入
私のクラスは、StorageManagerです。私は、ディスクからファイルを読み込むload()メソッドを単体テストしています。私は単体テストを実際のディスク上の実際のファイルに依存させてテストすることは望ましくありません。
だから、私はモックオブジェクトとI/O依存性を注入し、私のテスト中に、そのオブジェクトの動作を検証しようとしています。私は私のモックベースのユニットテストと「実際のコード」の両方に呼び出されたときに動作します構文でI/Oオブジェクトを使用する方法を見つけ出すことはできません。
単体テストから呼び出されたときに仕事をするようにコードを変更するにはどうすればよいですか(load()メソッドが好ましい)。あとで実際にテスト中のメソッドを呼び出すコード)?
注1:あなたはこれらのテストを実行した場合、テスト「モックなし」のファイル名VALID_FILENAMEと一致するディスク上のファイルを期待していることを覚えておいてください。
注2:pcallのtry/catchのような動作を使用して、1行または別の行を実行することを考えました(storageManager.lua行11 & 12を参照)。それが可能であっても、それはハックのように感じられ、後で投げたいかもしれないエラーをトラップする(out of load())。代替手段が見つからない場合は、このオプションで解説してください。
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
編集:
これらのクラスは、両方の試験に合格。 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
「パフォーマンスのためにioオブジェクトをローカライズする」ことを意味するわけではありませんが、「テスト中にグローバルioを[my] mockオブジェクトに置き換えたい」とします。私はstorageManager.luaでそれをやっていると思った:4?どのようにして「グローバルio」を適切に置き換えるのでしょうか?あなたはサンプルコードを提供できますか? – lance
あなたの編集は私に必要なものを与えました。変更されたコードを元の質問に編集しました。どうもありがとう。 – lance