lunarmodules / busted

Elegant Lua unit testing.
https://lunarmodules.github.io/busted/
MIT License
1.37k stars 184 forks source link

Mocking OOP objects #629

Open software-natives-docker opened 4 years ago

software-natives-docker commented 4 years ago

I wonder whether there's a better way to use busted in the following use case.

I'm using OOP as outlined here: http://lua-users.org/wiki/ObjectOrientationTutorial. Googling for OOP (object oriented, etc.) along with busted didn't yield any useful results, thus this issue.

I've got this class (production code):

local McModule = {}
McModule.__index = McModule
setmetatable(
    McModule,
    {
        __call = function(cls, ...)
            local self = setmetatable({}, cls)
            self:_init(...)
            return self
        end
    }
)

function McModule:_init()
    self.fcts = {}
end

function McModule:AddCommand(fct, name)
    self.fcts[name] = fct
end

function McModule:GetCommand(name)
    return self.fcts[name]
end

return McModule

I'm trying to mock functions and assert on the calls being made. Here's my test code


describe(
    'INCO API',

    function()
        local n, m, snapshot

        before_each(
            function()
                snapshot = assert:snapshot()
                m = mock(_G.MI.Mc)
                n = mock(getmetatable(_G.MI.Mc))
                -- ensure module is actually (re)loaded
                package.loaded['SHSSIStripHandlerSeq_06_StripHandling'] = nil
            end
        )

        after_each(
            function()
                snapshot:revert()
                -- Using these instead of snapshot:reverts() causes a "hanger" (program never ends, CPU 0%)
                -- mock.revert(m)
                -- mock.revert(n)
            end
        )

        it(
            'App.LoadStripWireDispense',
            function()
                require 'SHSSIStripHandlerSeq_06_StripHandling'

                assert.stub(n.AddCommand).was.called(4)
                assert.stub(n.AddCommand).was.called_with(match.is_ref(m), match.is_function(), 'App.LoadStripWireDispense')
                assert.stub(n.AddCommand).was.called_with(match.is_ref(m), match.is_function(), 'App.LoadStripPrePress')
                assert.stub(n.AddCommand).was.called_with(match.is_ref(m), match.is_function(), 'App.LoadStripInspect', match.is_table())
                assert.stub(n.AddCommand).was.called_with(match.is_ref(m), match.is_function(), 'App.LoadStripUnload', match.is_table())
            end
        )
    end
)

There are a couple of questions:

mecampbellsoup commented 2 years ago

Perhaps related but, is there a way to mock the return value of some mocked function? How are people mocking 3rd party modules that are integrated with their own code if not?