/Lunity

Simple-but-rich unit testing for Lua

Primary LanguageLua

Lunity v0.12

A simple single-file unit test system for Lua with a somewhat rich set of assertions and custom error messages. Features:

  • Lua 5.2,5.3 compatible.
  • Framework is a single file.
  • Control the order that tests are run (by renaming functions).
  • Can output ANSI (for conforming terminals) or HTML (for TextMate or e).
  • Sensible (to me) injection of functions while preserving global scope.
  • Rich set of assertions and custom error messages.
    (Including assertion for comparing tables of values.)

Simplest Usage

-- This magic line makes a `test` table available,
-- and makes all the assertions available to your tests
_ENV = require('lunity')()

-- Define tests that you want to run inside the `test` table
function test.simplest_assertion()
  assert(true, "If true isn't true, we are in big trouble.")  
end

-- At the end of your file, call `test()` to run the tests
test()

Robust Usage

-- You can optionally give a name to your test suite
_ENV = require('lunity')('check robustness')
 
function test:before()
  -- code here will be run before each test
  -- `self` is available to store information needed for the test
end
     
function test:after()
  -- run after each test, in case teardown is needed
end
     
-- Tests can have any name (other than 'before' or 'after')
-- The `self` table is the same scratchpad available to before()
function test:foo()
  assertTrue(42 == 40 + 2)
  assertFalse(42 == 40)
  assertEqual(42, 40 + 2)
  assertNotEqual(42, 40, "These better not be the same!")
  assertTableEquals({ a=42 }, { ["a"]=6*7 })
  -- See below for more assertions available
end

-- You can define helper functions for your tests to call with impunity
local function some_utility()
  return "excellent"
end

-- Tests will be run in alphabetical order of the entire function name
-- However, relying on the order of tests is an anti-pattern; don't do it
function test:bar()
  assertType(some_utility(), "string")
end

local allPassed = test{
  useANSI=false, -- turn off ANSI codes (colors/bold) in the output
  useHTML=true,  -- turn on  HTML markup in the output
  quiet=true,    -- silence print() and io.write() other than Lua during the tests
}

if not allPassed then os.exit(1) end

Assertions Available

The msg parameter is always optional; effort has been made to provide a helpful message if none is provided.

  • fail(msg) - instantly fail the test
  • assert(testCondition, msg) - fail if testCondition is either nil or false
  • assertEqual(actual, expected, msg) - fail if actual ~= expected
  • assertNotEqual(actual, expected, msg) - fail if actual == expected
  • assertTableEquals(actual, expected, msg) - recursively compare two tables and fail if they have any different keys or values
  • assertTrue(actual, msg) - fail if actual ~= true
  • assertFalse(actual, msg) - fail if actual ~= false
  • assertNil(actual, msg) - fail if actual ~= nil
  • assertNotNil(actual, msg) - fail if actual == nil
  • assertType(actual, expectedType, msg) - fail if type(actual) ~= expectedType, e.g. assertType(getResults(),"table","getResults() needs to return a table")
  • assertTableEmpty(actual, msg) - fail if actual is not a table, or if actual is a table with any keys (including a key with the value of false)
  • assertTableNotEmpty(actual, msg) - fail if actual is not a table, or if actual does not have any keys
  • assertSameKeys(table1, table2, msg) - fail if either table has a key not present in the other (good for set comparisons)
  • assertInvokable(value, msg) - fail if actual is not a function, or may not be invoked as one (via meta.__call)
  • assertErrors(invokable, ...) - call the function invokable passing along extra parameters, and fail if no errors are raised
  • assertDoesNotError(invokable, ...) - call the function invokable passing along extra parameters, and fail if any errors are raised

Helper Functions

The following functions are made available to your tests, though they do not count as assertions and will not cause a test failure on their own.

  • is_nil(value) - return true if value is nil
  • is_boolean(value) - return true if value is a boolean
  • is_number(value) - return true if value is a number
  • is_string(value) - return true if value is a string
  • is_table(value) - return true if value is a table
  • is_function(value) - return true if value is a function
  • is_thread(value) - return true if value is a thread
  • is_userdata(value) - return true if value is a userdata value

Note that while writing assert(is_table(value)) looks nicer in code than assertType(value, 'table'), the latter provides a better default error message to the user.

License

This work is licensed under the Creative Commons Attribution 3.0 United States License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/ or send a letter to

Creative Commons
171 Second Street, Suite 300
San Francisco, California, 94105, USA

Modification, reuse and redistribution permitted provided the following attribution and copyright line is included:

Copyright (c) 2012-2020 by Gavin Kistner (Phrogz)