0

I'm currently writing unit tests for a lua mod library using Busted. The file in question defines a module with some functions, then calls one of those functions at the bottom to initialize itself.

The problem I'm finding is that Busted appears to be evaluating the required-in file twice.

Test

it('does a thing', function()
    -- Some setup, replacing globals etc
    require('items')
    assert.are_equal(2, #Items._registry)
end)

Module

Items = { _registry = {} }
function Items.do_some_stuff() end
function some_util_func() end
function load_registry()
  print(debug.traceback())
  for i, itm in pairs(Items.do_some_stuff()) do
    Items._registry[i] = itm
  end
end

load_registry()

As you can see, although I've simplified the code and names, the structure is nothing out of the blue (as I understand.)

The test will always fail, because #Items._registry is always 0 (and dumping to the console verifies that). I tried printing inside the method and found it printed twice; then I tried using debug.traceback at the top of that unction and found the below. As you can see, the stack traceback is printing twice, suggesting the code is being evaluated twice.

Is this something anybody else has come across? Am I structuring my test wrong for this scenario? Or this a bug?


stack traceback:
    items.lua:96: in function 'load_registry'
    items.lua:109: in main chunk
    [C]: in function 'require'
    spec/items_pec.lua:50: in function <spec/items_spec.lua:39>
    [C]: in function 'xpcall'
    /usr/local/share/lua/5.2/busted/core.lua:178: in function 'safe'
    /usr/local/share/lua/5.2/busted/init.lua:40: in function 'executor'
    /usr/local/share/lua/5.2/busted/core.lua:312: in function </usr/local/share/lua/5.2/busted/core.lua:312>
    [C]: in function 'xpcall'
    /usr/local/share/lua/5.2/busted/core.lua:178: in function 'safe'
    ...
    /usr/local/share/lua/5.2/busted/core.lua:312: in function 'execute'
    /usr/local/share/lua/5.2/busted/block.lua:155: in function 'execute'
    /usr/local/share/lua/5.2/busted/init.lua:7: in function 'executor'
    /usr/local/share/lua/5.2/busted/core.lua:312: in function </usr/local/share/lua/5.2/busted/core.lua:312>
    [C]: in function 'xpcall'
    /usr/local/share/lua/5.2/busted/core.lua:178: in function 'safe'
    /usr/local/share/lua/5.2/busted/core.lua:312: in function 'execute'
    /usr/local/share/lua/5.2/busted/execute.lua:58: in function 'execute'
    /usr/local/share/lua/5.2/busted/runner.lua:174: in function </usr/local/share/lua/5.2/busted/runner.lua:11>
    /usr/local/lib/luarocks/rocks/busted/2.0.rc12-1/bin/busted:3: in main chunk
    [C]: in ?
stack traceback:
    items.lua:96: in function 'load_registry'
    items.lua:109: in main chunk
    [C]: in function 'require'
    spec/items_spec.lua:15: in main chunk
    [C]: in function 'xpcall'
    /usr/local/share/lua/5.2/busted/core.lua:178: in function 'safe'
    /usr/local/share/lua/5.2/busted/block.lua:146: in function 'execute'
    /usr/local/share/lua/5.2/busted/init.lua:7: in function 'executor'
    /usr/local/share/lua/5.2/busted/core.lua:312: in function </usr/local/share/lua/5.2/busted/core.lua:312>
    [C]: in function 'xpcall'
    /usr/local/share/lua/5.2/busted/core.lua:178: in function 'safe'
    /usr/local/share/lua/5.2/busted/core.lua:312: in function 'execute'
    /usr/local/share/lua/5.2/busted/execute.lua:58: in function 'execute'
    /usr/local/share/lua/5.2/busted/runner.lua:174: in function </usr/local/share/lua/5.2/busted/runner.lua:11>
    /usr/local/lib/luarocks/rocks/busted/2.0.rc12-1/bin/busted:3: in main chunk
    [C]: in ?
Thomas W
  • 14,757
  • 6
  • 48
  • 67
Andy Hunt
  • 1,053
  • 1
  • 11
  • 26
  • It's hard to tell what's going on here as your stack trace doesn't relate to your simplified code, and we don't know what load_registry does. I'd recommend refactoring your module using the new style: http://lua-users.org/wiki/ModulesTutorial – Chris Tanner Sep 06 '16 at 08:46
  • Fair point. I've added an implementation for the `load_registry` function and edited the names in the stack trace to match up with the example. – Andy Hunt Sep 07 '16 at 14:55
  • I've tried your example locally and I only get one output, what command are you running to test, is there any other code that might be causing problems? – Chris Tanner Sep 07 '16 at 15:02
  • I'm running simply `busted -t test_in_question -o plainTerminal`, on a Win 10 machine. This happens both through the new Linux subsystem and a standard Windows install of Lua. The module under test imports 2 additional modules, but those 2 modules are imported ahead of time by the spec and the globals they expose are mocked, with `_G.A = { some_func }`. The only other place this module is imported is in the tests of it functions (I've separated the tests for the its on-load behaviour to a separate spec) but by running with the `-t` flag I should be running the exact test only, right? – Andy Hunt Sep 07 '16 at 15:33

1 Answers1

1

The answer to this question lay in some detail I thought was extraneous but wasn't (see my comment).

In particular, I separated tests for the modules on-load behaviour from the tests for its various functions. Even when running with busted -t to target a specific test, the imports of the module under test were being evaluated in both specs; even when the require call was placed in the setup function for the root describe block.

By merging the two specs I was able to work around this double-loading.

Community
  • 1
  • 1
Andy Hunt
  • 1,053
  • 1
  • 11
  • 26