Lua Test Mocks
A mock is a stand-in value that replaces a real part during a test. It lets the test run without the real part.
A mock replaces a field
The test swaps one field for a simpler value. Calls to that field then see the mock.
local service = { price = function() return 100 end }
service.price = function() return 5 end
print(service.price())Restoration puts the original back
The saved value is written back after the test. The field then behaves as before.
local service = { price = function() return 100 end }
local saved = service.price
service.price = function() return 5 end
service.price = saved
print(service.price())The mock changes the code under test
The same function gives a different answer under the mock. After restoration it gives the real answer again.
local shop = { price = function() return 40 end }
local function checkout(s) return s.price() + 10 end
local saved = shop.price
shop.price = function() return 1 end
local mocked = checkout(shop)
shop.price = saved
local real = checkout(shop)
print(mocked, real)Example
local store = { price = function() return 40 end }
local function total(s) return s.price() * 2 end
local saved = store.price
store.price = function() return 7 end
print(total(store))
store.price = saved
print(total(store))Key points
- Mock: a mock replaces a field on a table for the test.
- Save first: the original value is saved before it is replaced.
- Run: the code under test runs while the mock is in place.
- Restore: the original value is put back after the test.
- Prove: calling the field after the test shows the original again.
In this example, the original price function is saved first, then replaced by a mock that returns 7. The total under the mock is 14. After restoration, calling the same total function gives 80, which proves the original is back.
Note
a mock that is never restored can leak into later tests.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What is the correct order for using a mock?