Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mocking out a lua module using package.preload

Tags:

mocking

lua

I'm trying to write a unit test against a single module function. This module collaborates with a few other modules, so I'd like to mock those modules out to isolate my system under test. Here's some simplified pseudo code:

local moduleFoo={}
local moduleBaz=  require("moduleBaz") 

moduleFoo.doSomething = function (arg) 

  if moduleBaz.bar.neatMethod(arg) then
     --does something interesting  
  end

end

return moduleFoo

And here's the code for moduleBaz

local moduleBaz={}
moduleBaz.bar= {}

moduleBaz.bar.neatMethod=function(arg)
   --does something neat
end
return moduleBaz

I'm trying to use the package.preload function to inject a mock instance of moduleBaz before my tests run, but it doesn't appear to work (i.e. the real instance of the moduleBaz is used in the test, not my mock)

Here's some psueudo test code:

    package.loaded.moduleBaz= nil
    local moduleBaz = {}
    moduleBaz.bar = {}
    moduleBaz.bar.neatMethod= function(guid) return true end

    package.preload['moduleBaz'] = function ()
        return moduleBaz
    end

   local foo= require("moduleFoo")
   foo.doSomething('asdasdasda')--real moduleBaz is called, not my mock!

Any ideas what I'm doing wrong? I'm very new to Lua, and not at all comfortable with how scope is handled in the language!

like image 816
Mitch A Avatar asked Feb 20 '23 00:02

Mitch A


1 Answers

You seem to be missing a return statement in your moduleBaz code

return moduleBaz

Why not use package.loaded as it gives you a simpler interface? package.loaded.moduleBaz would simply need to include whatever you'd want to return from your moduleBaz code. Something like this should work or give you an idea:

package.loaded.moduleBaz = {
  bar = {
    neatmethod = function(arg)
      -- your mock code here
    end,
  }
}

Then require('moduleBaz') would simply return that object you just created.

I cannot reproduce the issue with your setup either. The files I used are below; notice that I added return moduleBaz as I described above, but this is the only change I made:

file moduleBaz.lua:

local moduleBaz={}
moduleBaz.bar= {}
moduleBaz.bar.neatMethod=function(arg)
  print "baz"
  return true
end
return moduleBaz

file moduleFoo.lua:

local moduleFoo={}
local moduleBaz=  require("moduleBaz") 
  moduleFoo.doSomething = function (arg) 
  if moduleBaz.bar.neatMethod(arg) then
    print "foo"
  end
end
return moduleFoo

file testFoo.lua

package.loaded.moduleBaz= nil
local moduleBaz = {}
moduleBaz.bar = {}
moduleBaz.bar.neatMethod= function(guid) print "mock" return true end

package.preload['moduleBaz'] = function ()
    return moduleBaz
end

local foo= require("moduleFoo")
foo.doSomething('asdasdasda')--real moduleBaz is called, not my mock!

When I run this, I get mock\nfoo\n printed as expected.

like image 173
Paul Kulchenko Avatar answered Feb 23 '23 00:02

Paul Kulchenko