.. _getting-started: Getting started with LuaUnit =================================== This section will guide you through a step by step usage of *LuaUnit* . The full source code of the example below is available in the : :ref:`source_code_example` or in the file *my_test_suite.lua* in the doc directory. Setting up your test script --------------------------- To get started, create your file *my_test_suite.lua* . The script should import LuaUnit:: lu = require('luaunit') The last line executes your script with LuaUnit and exit with the proper error code:: os.exit( lu.LuaUnit.run() ) Now, run your file with:: lua my_test_suite.lua It prints something like:: Ran 0 tests in 0.000 seconds, 0 successes, 0 failures OK Now, your testing framework is in place, you can start writing tests. Writing tests ----------------- LuaUnit scans all variables that start with *test* or *Test*. If they are functions, or if they are tables that contain functions that start with *test* or *Test*, they are run as part of the test suite. Note that this prefix can be ajusted with command-line options (see :ref:`command-line-options`). So just write a function whose name starts with test. Inside test functions, use the assertions functions provided by LuaUnit, such as :lua:func:`assertEquals`. Let's see that in practice. Suppose you want to test the following add function:: function add(v1,v2) -- add positive numbers -- return 0 if any of the numbers are 0 -- error if any of the two numbers are negative if v1 < 0 or v2 < 0 then error('Can only add positive or null numbers, received '..v1..' and '..v2) end if v1 == 0 or v2 == 0 then return 0 end return v1+v2 end You write the following tests:: function testAddPositive() lu.assertEquals(add(1,1),2) end function testAddZero() lu.assertEquals(add(1,0),0) lu.assertEquals(add(0,5),0) lu.assertEquals(add(0,0),0) end :lua:func:`assertEquals` is the most commonly used assertion function. It verifies that both argument are equals, in the order actual value, expected value. Rerun your test script (``-v`` is to activate a more verbose output):: $ lua my_test_suite.lua -v It now prints:: Started on 02/19/17 22:15:53 TestAdd.testAddPositive ... Ok TestAdd.testAddZero ... Ok ========================================================= Ran 2 tests in 0.003 seconds, 2 successes, 0 failures OK You always have: * the date at which the test suite was started * the group to which the function belongs (usually, the name of the function table, and ** for all direct test functions) * the name of the function being executed * a report at the end, with number of executed test, number of non selected tests if any, number of failures, number of errors (if any) and duration. The difference between failures and errors are: * luaunit assertion functions generate failures * any unexpected error during execution generates an error * failures or errors during setup() or teardown() always generate errors If we continue with our example, we also want to test that when the function receives negative numbers, it generates an error. Use :lua:func:`assertError` or even better, :lua:func:`assertErrorMsgContains` to also validate the content of the error message. There are other types or error checking functions, see :ref:`error-assertions` . Here we use :lua:func:`assertErrorMsgContains` . First argument is the expected message, then the function to call and the optional arguments:: function testAddError() lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3) end Now, suppose we also have the following function to test:: function adder(v) -- return a function that adds v to its argument using add function closure( x ) return x+v end return closure end We want to test the type of the value returned by adder and its behavior. LuaUnit provides assertion for type testing (see :ref:`type-assertions` ). In this case, we use :lua:func:`assertIsFunction`:: function testAdder() f = adder(3) lu.assertIsFunction( f ) lu.assertEquals( f(2), 5 ) end Grouping tests, setup/teardown functionality ------------------------------------------------ When the number of tests starts to grow, you usually organise them into separate groups. You can do that with LuaUnit by putting them inside a table (whose name must start with *Test* or *test* ). For example, assume we have a second function to test:: function div(v1,v2) -- divide positive numbers -- return 0 if any of the numbers are 0 -- error if any of the two numbers are negative if v1 < 0 or v2 < 0 then error('Can only divide positive or null numbers, received '..v1..' and '..v2) end if v1 == 0 or v2 == 0 then return 0 end return v1/v2 end We move the tests related to the function add into their own table:: TestAdd = {} function TestAdd:testAddPositive() lu.assertEquals(add(1,1),2) end function TestAdd:testAddZero() lu.assertEquals(add(1,0),0) lu.assertEquals(add(0,5),0) lu.assertEquals(add(0,0),0) end function TestAdd:testAddError() lu.assertErrorMsgContains('Can only add positive or null numbers, received 2 and -3', add, 2, -3) end function TestAdd:testAdder() f = adder(3) lu.assertIsFunction( f ) lu.assertEquals( f(2), 5 ) end -- end of table TestAdd Then we create a second set of tests for div:: TestDiv = {} function TestDiv:testDivPositive() lu.assertEquals(div(4,2),2) end function TestDiv:testDivZero() lu.assertEquals(div(4,0),0) lu.assertEquals(div(0,5),0) lu.assertEquals(div(0,0),0) end function TestDiv:testDivError() lu.assertErrorMsgContains('Can only divide positive or null numbers, received 2 and -3', div, 2, -3) end -- end of table TestDiv Execution of the test suite now looks like this:: Started on 02/19/17 22:15:53 TestAdd.testAddError ... Ok TestAdd.testAddPositive ... Ok TestAdd.testAddZero ... Ok TestAdd.testAdder ... Ok TestDiv.testDivError ... Ok TestDiv.testDivPositive ... Ok TestDiv.testDivZero ... Ok ========================================================= Ran 7 tests in 0.006 seconds, 7 successes, 0 failures OK When tests are defined in tables, you can optionally define two special functions, *setUp()* and *tearDown()*, which will be executed respectively before and after every test. These function may be used to create specific resources for the test being executed and cleanup the test environment. For a practical example, imagine that we have a *log()* function that writes strings to a log file on disk. The file is created upon first usage of the function, and the filename is defined by calling the function *initLog()*. The tests for these functions would take advantage of the *setup/teardown* functionality to prepare a log filename shared by all tests, make sure that all tests start with a non existing log file name, and delete the log filename after every test:: TestLogger = {} function TestLogger:setUp() -- define the fname to use for logging self.fname = 'mytmplog.log' -- make sure the file does not already exists os.remove(self.fname) end function TestLogger:testLoggerCreatesFile() initLog(self.fname) log('toto') -- make sure that our log file was created f = io.open(self.fname, 'r') lu.assertNotNil( f ) f:close() end function TestLogger:tearDown() -- cleanup our log file after all tests os.remove(self.fname) end .. Note:: *Errors generated during execution of setUp() or tearDown() functions are considered test failures.* .. Note:: *For compatibility with luaunit v2 and other lua unit-test frameworks, setUp() and tearDown() may also be named setup(), SetUp(), Setup() and teardown(), TearDown(), Teardown().* .. _Using-the-command-line: Using the command-line ---------------------------------- You can control the LuaUnit execution from the command-line: *Output format** Choose the test output format with ``-o`` or ``--output``. Available formats are: * text: the default output format * nil: no output at all * tap: TAP format * junit: output junit xml Example of non-verbose text format:: $ lua doc/my_test_suite.lua ....... Ran 7 tests in 0.003 seconds, 7 successes, 0 failures OK Example of TAP format:: $ lua doc/my_test_suite.lua -o TAP 1..7 # Started on 02/19/17 22:15:53 # Starting class: TestAdd ok 1 TestAdd.testAddError ok 2 TestAdd.testAddPositive ok 3 TestAdd.testAddZero ok 4 TestAdd.testAdder # Starting class: TestDiv ok 5 TestDiv.testDivError ok 6 TestDiv.testDivPositive ok 7 TestDiv.testDivZero # Ran 7 tests in 0.007 seconds, 7 successes, 0 failures Output formats may also be controlled by the following environment variables: * LUAUNIT_OUTPUT: output format to use * LUAUNIT_JUNIT_FNAME: for junit output format, name of the xml file For a more detailed overview of all formats and their verbosity see the section :ref:`output-formats` . **List of tests to run** You can list some test names on the command-line to run only those tests. The name must be the exact match of either the test table, the test function or the test table and the test method. The option may be repeated. Example:: -- Run all TestAdd table tests and one test of TestDiv table. $ lua doc/my_test_suite.lua TestAdd TestDiv.testDivError -v Started on 02/19/17 22:15:53 TestAdd.testAddError ... Ok TestAdd.testAddPositive ... Ok TestAdd.testAddZero ... Ok TestAdd.testAdder ... Ok TestDiv.testDivError ... Ok ========================================================= Ran 5 tests in 0.003 seconds, 5 successes, 0 failures OK **Including / excluding tests** The most flexible approach for selecting tests to use the include and exclude functionality. With ``--pattern`` or ``-p``, you can provide a lua pattern and only the tests that contain the pattern will actually be run. Example:: -- Run all tests of zero testing and error testing -- by using the magic character . $ lua my_test_suite.lua -v -p Err.r -p Z.ro For our test suite, it gives the following output:: Started on 02/19/17 22:15:53 TestAdd.testAddError ... Ok TestAdd.testAddZero ... Ok TestDiv.testDivError ... Ok TestDiv.testDivZero ... Ok ========================================================= Ran 4 tests in 0.003 seconds, 4 successes, 0 failures, 3 non-selected OK The number of tests ignored by the selection is printed, along with the test result. The pattern can be any lua pattern. Be sure to exclude all magic characters with % (like -+?*) and protect your pattern from the shell interpretation by putting it in quotes. You can also exclude tests that match some patterns: Example:: -- Run all tests except zero testing and except error testing $ lua my_test_suite.lua -v -x Error -x Zero For our test suite, it gives the following output:: Started on 02/19/17 22:29:45 TestAdd.testAddPositive ... Ok TestAdd.testAdder ... Ok TestDiv.testDivPositive ... Ok ========================================================= Ran 3 tests in 0.003 seconds, 3 successes, 0 failures, 4 non-selected OK You can also combine test selection and test exclusion. See :ref:`flexible-test-selection` Conclusion ---------- You now know enough of LuaUnit to start writing your test suite. Check the reference documentation for a complete list of assertions, command-line options and specific behavior.