lunarmodules / busted

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

How to mock or stub a local function #607

Closed kakascx closed 5 years ago

kakascx commented 5 years ago

The following is the code to be tested, and they are all in json2xml.lua

--- json2xml.lua
local function FirstToUpper(str)
  return (str:gsub("^%l", string.upper))
end

local function LabBefore(tab,label)
  tab[#tab+1]="<"
  tab[#tab+1]=FirstToUpper(label)
  tab[#tab+1]=">"
end

if _TEST then
  M._IsArrayTable = IsArrayTable
  M._FirstToUpper = FirstToUpper
end

The following is unit test code:

   local json2xml = require "json2xml"
   describe("unit test of LabBefore",function()
        it("should be <label>",function()
        local tab = {}
        local key = key
        json2xml._LabBefore(tab,key)
        local str = table.concat(tab)
        assert.are.same("<key>",str)
        end)
    end)

When I attempted to make a unit test of LabBefore ,it reported the error :

unit test of json2xml.lua  unit test of LabBefore should be <label>
./json2xml.lua:54: attempt to index local 'str' (a nil value)

How could I mock or stub the function FirstToUpper? Or some way to invoke it?

Tieske commented 5 years ago

not sure why you want to mock it (also wouldn't know how). Your problem is not with FirstToUpper but with the unit test. Specifically the line local key = key, most likely it should have been local key = "key". (using a linter like luacheck would have immediately triggered on this global access.)

So you could add an assertion to FirstToUpper like;

local function FirstToUpper(str)
  assert(type(str) == "string", "1st argument must be a string")
  return (str:gsub("^%l", string.upper))
end

and then add unit tests for it to prove it only accepts strings.

kakascx commented 5 years ago

not sure why you want to mock it (also wouldn't know how). Your problem is not with FirstToUpper but with the unit test. Specifically the line local key = key, most likely it should have been local key = "key". (using a linter like luacheck would have immediately triggered on this global access.)

So you could add an assertion to FirstToUpper like;

local function FirstToUpper(str)
  assert(type(str) == "string", "1st argument must be a string")
  return (str:gsub("^%l", string.upper))
end

and then add unit tests for it to prove it only accepts strings.

The point is I wanna to make the unit test of LabBefore not 'FirstToUpper'. When I attempted to make the function LabBefore , it invokes FirstToUpper in LabBefore and reports an error. I wonder if it was the influence of the function FirstToUpper. For this reason I tried to mock the FirstToUpper to avoid external influence

DorianGray commented 5 years ago

Then you need to expose FirstToUpper in the

if _TEST then
  M._IsArrayTable = IsArrayTable
  M._FirstToUpper = FirstToUpper
end

block. I don't think there is a way outside of doing nasty vm internal stuff to do exactly what you're asking.