Skip to content

Refactor to be testable

adamwagner edited this page Oct 10, 2020 · 1 revision

Isolate test environment

https://github.com/hoelzro/lua-procure procure.isolated(name) This function behaves exactly like procure(), except the module specified by name is loaded in an isolated environment (it cannot make changes to the global environment). This is to allow users who want to keep a clean global environment to use modules that "misbehave" in this regard.

It's not entirely impossible for isolated modules to alter the global
environment; while naïve global assignment (assigning to a variable not declared
with local) and assigning to _G will be intercepted, assigning to keys in the
value returned by getfenv(0) (for example) will not. I feel this is a proper
balance between cleanliness and flexibility.

Libs enabling best-practices for testable code

Inversion of control https://github.com/basiliscos/lua-gear

Dependency injection https://fperrad.frama.io/lua-Coat/inject/

Lua design patterns

General overview of standard design patterns https://www.youtube.com/watch?v=_BpmfnqjgzQ&list=PLrhzvIcii6GNjpARdnO4ueTUAVR9eMBpc&index=2

https://github.com/floydawong/lua-patterns https://github.com/woshihuo12/LuaDesignPattern http://lua-users.org/wiki/LuaTypeChecking

Reactive libs

lua-reactor React-style ui component system for Lua 2017

The lifecycle module: https://github.com/talldan/lua-reactor/blob/master/src/reactor/reconcile.lua

luact Build reactive user interfaces on Lua 2020

https://github.com/LXSMNSYC/luact

coutil Syncronization of coroutines using events and promises. https://github.com/renatomaia/coutil

Event libs

https://github.com/ejmr/Luvent

React when table values changes

Did not work https://github.com/ZichaoNickFox/ReactiveTable (2016) https://github.com/Phrogz/notifitable (2014)

Not tested https://github.com/pfzq303/dataBind-lua https://github.com/Anti-Magic/rdatabinding (looks good!)

Worked! https://github.com/ayongm2/TableMonitor (2017) https://github.com/mainlei/bindingtable/blob/master/bindingtable.lua (2020) ✅

However, this is also pretty simple to build from scratch:

local function listener(k,v)
    print( "new entry added: \n\tKey = " .. k .. "\n\tValue = " .. v)
end

local protectedTable = {}

local metaTable = {
    __index = function (t,k)
        return protectedTable[k]
    end,

    __newindex = function (t,k,v)
        protectedTable[k] = v   -- update original table
        listener(k,v)
    end,

    __ipairs = function(table)
        return ipairs(protectedTable)
    end,

    __pairs = function(table)
        return pairs(protectedTable)
    end
}

local t = setmetatable({},metaTable)

-- test
t.text = "Hello!"
print(t.text)

State machines

https://github.com/emiruz/decide https://github.com/kyleconroy/lua-state-machine

local machine = require('statemachine')

local fsm = machine.create({
  initial = 'green',
  events = {
    { name = 'warn',  from = 'green',  to = 'yellow' },
    { name = 'panic', from = 'yellow', to = 'red'    },
    { name = 'calm',  from = 'red',    to = 'yellow' },
    { name = 'clear', from = 'yellow', to = 'green'  }
}})