"Hello Test" using busted

I tried finding a way to unit-test Ardupilot-Lua scripts. As I failed to find anything documented, I figured it out myself and wanted to share my findings.

Looking around, busted seemed to be a recommended framework for Lua testing (but it’s probably not necessary to use it).

As an example, I’ve written a simple Hello World script:

--helloworld.lua
function update()
    gcs:send_text(0, "HelloWorld")
    return update, 5000 -- check again in 15 seconds
  end
  
  gcs:send_text(0, "HelloWorld loaded")
  return update, 5000 -- first message may be displayed 5 seconds after start-up

Here is the very simplistic test:

-- test_helloworld.lua
local busted = require('busted')

-- Mock dependencies
gcs = {
    send_text = function(self, severity, text)
        print(string.format("GCS Message [%d]: %s", severity, text))
  end
}

-- Override global variables
_G.gcs = gcs

-- Load the script to test
dofile("helloworld.lua")

describe("HelloWorld", function()
  it("should send 'HelloWorld' message on update", function()
    -- Capture the output
    local output = {}
    gcs.send_text = function(self, severity, text)
        table.insert(output, {severity = severity, text = text})
    end

    -- Run the update function
    local next_update, delay = update()

    -- Check the output
    assert.are.equal(0, output[1].severity)
    assert.are.equal("HelloWorld", output[1].text)
    assert.are.equal(update, next_update)
    assert.are.equal(5000, delay)
  end)

  it("should send 'HelloWorld loaded' message on load", function()
    -- Capture the output
    local output = {}
    gcs.send_text = function(self, severity, text)
        table.insert(output, {severity = severity, text = text})
    end

    -- Reload the script to capture the load message
    dofile("helloworld.lua")

    -- Check the output
    assert.are.equal(0, output[1].severity)
    assert.are.equal("HelloWorld loaded", output[1].text)
  end)
end)

You can run it with busted test_batterychecker.lua

A few points I stumbled about:

  • When calling functions using a colon (ex. gcs:send_text), the mock needs to have a self parameter as the first parameter
  • The update function needs to be globally accessible, at least the way I use it here

If anyone has any improvement suggestions, I’d be happy about them, I mainly wanted to kickstart a discussion about lua script testing