mocking out a lua module using package.preload - 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!

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.

Related

Can anyone tell me that the error "calling xxxx on bad self" shows

I use lua in Unity. When I call the function **TryDisableHeadWear **, there are some error I can't understand.
calling 'GetSurfaceName' on bad self (string expected, got nil)
function def:TryDisableHeadWear()
if not self:CheckSurfaceName(self._hat_go) then
self._hat_go:SetActive(false)
end
end
function def:CheckSurfaceName(obj)
local surface_name = self:GetSurfaceName(obj)
return head_wear_surface[surface_name] ~= nil
end
local reg = "(%w+)"
function def:GetSurfaceName(obj)
if not obj then return end
local root_obj = self:GetSurfaceObj(obj)
local surface_obj_name = root_obj and root_obj.name
return surface_obj_name and string.match(surface_obj_name, reg)
end
function def:GetSurfaceObj(obj)
if string.find(obj.name, "Surface") then
return obj
else
local parent = obj.transform.parent
if not parent then return end
return self:GetSurfaceObj(parent.gameObject)
end
end
Can anyone tell me what the error means?
I try to call the function in normal environment. I get no error and everything goes well. But where are some error report in firebase that means the code above has bugs

How to inherit method?

I want to inherit method "GetName" or other methods from "Create" for "CreateInherited" and i want save unique methods from "CreateInherited" (like "GetInheritName"), but i dont know how.
My test code:
local MainTbl = {}
function MainTbl:Create(name)
local tbl = {}
tbl.name = name or 'Null'
function tbl:GetName()
return self.name
end
setmetatable(tbl, self)
self.__index = self
return tbl
end
function MainTbl:CreateInherited(name)
local tbl = {}
tbl.name = name or 'Null'
function tbl:GetInheritName()
return self.name
end
setmetatable(tbl, self)
self.__index = self
return tbl
end
local Man = MainTbl:Create('Man')
local Woman = MainTbl:CreateInherited('Woman')
print(Man:GetName())
print(Woman:GetName())
print(Woman:GetInheritName())
If I understand you, you're trying to put two different constructors into a single class. Notice that Create does most of the work that CreateInherited needs to do, so you can save yourself a lot of repeated code by calling Create inside CreateInherited. Instead of starting with an empty table, you can start with a fully formed instance from Create and add a method to it.
function MainTbl:CreateInherited(name)
local tbl = self:Create(name)
function tbl:GetInheritName()
return self.name
end
return tbl
end

Meta table error

I am trying to set up a toy example for threading in torch but I am getting an error from running the code below. I think it might just be the way I set up the table but I am not sure.
Threads = require 'threads'
Threads.serialization('threads.sharedserialize')
DataThreads = {}
DataThreads.__index = DataThreads
local result = {}
local unpack = unpack and unpack or table.unpack
function DataThreads.new(nThreads,opt_)
local self = {}
opt_ = opt_ or {}
self.threads = Threads(nThreads,
function()
print("background stuff")
end
)
self.threads:synchronize()
-- The below for loop is causing the error but the same :addjob() works later on
for i=1, nThreads do
self.threads:addjob(self._getFromThreads, self._pushResult)
end
return setmetatable(self,DataThreads)
end
function DataThreads._getFromThreads()
x,y = torch.uniform(),torch.uniform()
return x,y
end
function DataThreads._pushResult(...)
local res = {...}
if res == nil then
self.threads:synchronize()
end
result[1] = res
end
function DataThreads:getBatch()
self.threads:addjob(self._getFromThreads, self._pushResult)
self.threads:dojob()
local res = result[1]
result[1] = nil
if torch.type(res) == 'table' then
return unpack(res)
end
print(type(res))
return res
end
d = DataThreads.new(4)
The error occurs in :addjob() in the .new function. However calling the same :addjob() later on in the :getBatch() function works. Am I not allowed to call the ._getFromThreads(), ._getFromThreads() functions before the metatable is set? Here is the error, which I think means ._getFromThreads() is not returning anything;
/home/msmith/torch/install/bin/luajit: ...e/msmith/torch/install/share/lua/5.1/threads/threads.lua:215: function callback expected
stack traceback:
[C]: in function 'assert'
...e/msmith/torch/install/share/lua/5.1/threads/threads.lua:215: in function 'addjob'
threads.lua:21: in function 'new'
threads.lua:54: in main chunk
When the code in your new function runs the metatable hasn't been set up yet so when you use self._getFromThreads and self._pushResult there's nothing there and you get nil back and that's not valid.
It works after the new function returns because at that point the metatable has been added so the lookups use the __index metamethod to look the entries up.
You can do
local self = setmetatable({}, DataThreads)
to set the metatable up immediately and then just
return self
at the end.

overriding updateGradInput method in torch is not working for my self defined module

I implemented a module called sharedModule for my own use. And I have overriden the updateGradInput method below:
function SharedModule:updateGradInput(input, gradOutput)
test_grad = {}
print("call updateGradInput")
test_input = input
test_gradOutput = gradOutput
assert(type(gradOutput) == 'table' and #input == #gradOutput)
local T = #input
for t = 1, T do
self.gradInput[t] = self.clones[t]: updateGradInput(input[t], gradOutput[t])
test_grad[t] = self.gradInput[t]
end
print(#self.gradInput) -- print normal value
--self.gradInput = test_grad --
return self.gradInput -- empty, ???
end
However, when i call backward method on my module, the self.gradInput field is not updated, what's the problem, any one can help me out?
backward method will call two methods named updateGradInput and accGradParams, turns out that the error occurs in accGradParams because of typos

attempt to index local 'self' using MOAICoroutine in Lua

I am just starting with MOAI and I am trying to create a traditional game loop using MOAICoroutine. The problem is that when I pass it the function that is part of a "class" that is built using 30log, it returns an error. It seems to continue to function, but I would like to fix the error. My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon. Here is the code:
class = require "30log.30log"
GameSystem = class ()
function GameSystem:__init(Name, Title)
self.Name = Name
self.Title = Title
self.Ready = false
end
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
--self:Start()
return true
else
print("Init failed.")
return false
end
end
function GameSystem:Init()
print("Initializing Game System")
if not self:InitTimer() then return false end
if not self:InitWindow(640,480) then return false end
if not self:InitViewport() then return false end
if not self:InitGraphics() then return false end
if not self:InitSound() then return false end
if not self:InitInput() then return false end
self.Ready = true
return true
end
function GameSystem:Start()
print("Starting Game System")
while self.Ready do
self:UpdateTimer()
self:UpdateGraphics()
self:UpdateSound()
self:UpdateInput()
coroutine.yield()
end
end
function GameSystem:InitTimer()
return true
end
function GameSystem:InitWindow(width, height)
print("Initializing Window")
return true
end
function GameSystem:InitViewport()
print("Initializing Viewport")
return true
end
function GameSystem:InitGraphics()
print("Initializing Graphics")
return true
end
function GameSystem:InitSound()
print("Initializing Sound")
return true
end
function GameSystem:InitInput()
print("Initializing Input")
return true
end
function GameSystem:UpdateTimer()
--print("Updating Timer")
return true
end
function GameSystem:UpdateGraphics()
--print("Updating Graphics")
return true
end
function GameSystem:UpdateSound()
--print("Updating Sound")
return true
end
function GameSystem:UpdateInput()
--print("Updating Input")
return true
end
Is the 30log class code causing this problem? I have tried various things. I am pretty sure the self it is trying to access is the first argument i.e. mytable.myfunction(self, myarg). Any ideas to fix this nil value reference. The error actually occurred on the second line inside the Start function (while self.Ready do).
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon.
How would it be calling the function using dot notion (or colon notation)? What would be on the left side of the period or colon? You haven't passed it an object, only a function. The fact that it's caller was storing that function in a table is completely unknown to it. It just receives a function, and calls it.
If you want your coroutine to start with a method call, do that in the function you pass to coroutine.start:
self.Thread = MOAICoroutine.new ()
self.Thread:run(function() self:Start() end)
The point is that:
function GameSystem:Start()
end
Is exactly equivalent to:
function GameSystem.Start(self)
end
Is exactly equivalent to:
GameSystem.Start = function(self)
end
Is equivalent to:
function Foobar(self)
end
GameSystem.Start = Foobar
If I call:
print(Foobar)
print(GameSystem.Start)
print(someGameSystemInstance.Start)
print receives the same value. In Lua, a function is a function is a function, it's not "tainted" in some way by being stored in a table, such that a third party with a reference to the function can know that you want it to be called as a method to some particular 'class instance.

Resources