سؤال

أنا مبتدئ لوا.أقوم باختبار وحدة كود Lua 5.1 باستخدام لونيتي و ليموك.

صفي هو StorageManager.أنا أقوم باختبار طريقة التحميل () الخاصة بها، والتي تقوم بتحميل الملفات من القرص.لا أريد أن تعتمد اختبارات وحدتي على الملفات الفعلية الموجودة على القرص الفعلي لاختبار ذلك.

لذا، أحاول حقن تبعية الإدخال/الإخراج بكائن وهمي والتحقق من سلوك هذا الكائن أثناء الاختبار.لا يمكنني معرفة كيفية استخدام كائن الإدخال/الإخراج مع بناء جملة يعمل عند استدعائه بواسطة اختبار الوحدة الوهمي الخاص بي و"الرمز الحقيقي".

كيف يمكنني تغيير الكود (يُفضل استخدام طريقة التحميل () بحيث يقوم بعمله عند استدعائه من أي اختبار للوحدة (يعد الكود الذي لا يحتوي على النموذج مؤقتًا حتى أكتشف ذلك - إنه يشبه الكود الذي سوف في وقت لاحق استدعاء الطريقة قيد الاختبار)؟

ملاحظة 1:إذا قمت بتشغيل هذه الاختبارات، فتذكر أن اختبار "بدون وهمية" يتوقع وجود ملف على القرص يتطابق اسمه مع VALID_FILENAME.

ملاحظة 2:فكرت في استخدام سلوك المحاولة/الالتقاط الخاص بـ pcall لتنفيذ سطر واحد أو آخر (راجع سطر 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}

مدير التخزين. لوا:

 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
هل كانت مفيدة؟

المحلول

أعتقد أنك تجعل المشكلة أكثر صعوبة مما ينبغي.

على افتراض أن وحدة StorageManager.lua لا تقوم بنفسها بترجمة ملف io الوحدة، فكل ما عليك فعله هو استبدال الوحدة global io مع كائنك الوهمي أثناء إجراء الاختبار.

إذا قامت الوحدة بترجمة ملف io الكائن للأداء، فإنك ستحتاج إلى إدخال القيمة الجديدة لـ io قبل تحميل الوحدة.قد يعني هذا أنك بحاجة إلى إجراء مكالمة إلى require جزء من إعداد حالة الاختبار (والتنظيف المطابق الذي يزيل جميع آثار الوحدة من package.loaded و _G) بحيث يمكن الاستهزاء به بشكل مختلف في حالات الاختبار المختلفة.WinImage

يحرر:

من خلال ترجمة وحدة نمطية للأداء، أعني لغة Lua الخاصة بنسخ أساليب الوحدة إلى المتغيرات المحلية في مساحة اسم الوحدة.على سبيل المثال:

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

إذا قمت بذلك، فإن الإشارات إلى وحدات المخزون io و math مصنوعة في هذه اللحظة require "somemodule" يتم تنفيذ.استبدال أي من هاتين الوحدتين بعد الاتصال بـ require() مع نسخة مستهزئة لن تكون فعالة.

للسخرية بشكل فعال من الوحدة المستخدمة مع هذا المصطلح، يجب أن يكون لديك الكائن الوهمي في مكانه قبل الدعوة الى require().

فيما يلي كيفية استبدال كائن io طوال مدة المكالمة في حالة الاختبار:

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

ربما لا أقوم باستعادة الكائن الحقيقي في اللحظة المناسبة تمامًا، وهذا لم يتم اختباره، لكنه يجب أن يوجهك في الاتجاه الصحيح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top