Unit Testing

lua-users home
wiki

Unit testing is about testing your code during development, not in production. Typically you start by preparing the testing environment, writing some code that calls production code and check expected results with actual results.

Lua has these frameworks to do that:

Both have mostly the main feature set, which is:

Commercial Lua testing tools are available from Software Verification[1].

luaunit

I am going to provide an example for the second one (luaunit) since I am more familiar with it. The example is pretty simple to understand.


-- Some super function to test
function my_super_function( arg1, arg2 ) return arg1 + arg2 end

-- Unit testing starts
require('luaunit')

TestMyStuff = {} --class
    function TestMyStuff:testWithNumbers()
        a = 1
        b = 2
        result = my_super_function( a, b )
        assertEquals( type(result), 'number' )
        assertEquals( result, 3 )
    end

    function TestMyStuff:testWithRealNumbers()
        a = 1.1
        b = 2.2
        result = my_super_function( a, b )
        assertEquals( type(result), 'number' )
        -- I would like the result to be always rounded to an integer
        -- but it won't work with my simple implementation
        -- thus, the test will fail
        assertEquals( result, 3 )
    end

-- class TestMyStuff

luaUnit:run()

When you run it, you get:

shell $ lua use_luaunit1.lua
>>>>>> TestMyStuff
>>> TestMyStuff:testWithNumbers
Ok
>>> TestMyStuff:testWithRealNumbers
use_luaunit1.lua:25: expected: 3.3, actual: 3
Failed

Success : 50% - 1 / 2

The testing framework reports the file and line that caused the error, and some additional information.

When your program grows, you need more and more test cases. The next example is slightly more complicated.

-- Some super function to test
function my_super_function( arg1, arg2 ) return arg1 + arg2 end
function my_bad_function( arg1, arg2 ) return arg1 - arg2 end

-- Unit testing starts
require('luaunit')

-- now, we perform all the tests on int in one test class
-- and the tests on float in another one
-- when your test grows, you will have many test classes

TestWithInt = {} --class
    function TestWithInt:setUp() 
        -- this function is run before each test, so that multiple
        -- tests can share initialisations
        self.a = 1
        self.b = 2
    end

    function TestWithInt:tearDown() 
        -- this function is executed after each test
        -- here, we have nothing to do so we could have avoid
        -- declaring it
    end

    function TestWithInt:testSuperFunction()
        result = my_super_function( self.a, self.b )
        assertEquals( type(result), 'number' )
        assertEquals( result, 3 )
    end

    function TestWithInt:testBadFunction()
        result = my_bad_function( self.a, self.b )
        assertEquals( type(result), 'number' )
        assertEquals( result, -1 )
    end

    function TestWithInt:testThatFails()
        -- you can test anything with assertEquals
        assertEquals( self.a, 1 )
        assertEquals( type(self.a), 'number' )
        -- will fail
        assertEquals( 'hop', 'bof' )
    end
-- class TestWithInt

TestWithFloat = {} --class
    function TestWithFloat:setUp() 
        -- this function is run before each test, so that multiple
        -- tests can share initialisations
        self.a = 1.1
        self.b = 2.1
    end

    function TestWithFloat:tearDown() 
        -- this function is executed after each test
        -- here, we have nothing to do so we could have avoid
        -- declaring it
    end

    function TestWithFloat:testSuperFunction()
        result = my_super_function( self.a, self.b )
        assertEquals( type(result), 'number' )
        -- will fail
        assertEquals( result, 3 )
    end

    function TestWithFloat:testBadFunction()
        result = my_bad_function( self.a, self.b )
        assertEquals( type(result), 'number' )
        -- will work, but only by chance :-)
        assertEquals( result, -1 )
    end
-- class TestWithFloat

luaUnit:run()

Run it:

shell $ lua use_luaunit2.lua
>>>>>> TestWithFloat
>>> TestWithFloat:testSuperFunction
use_luaunit2.lua:66: expected: 3.2, actual: 3
Failed
>>> TestWithFloat:testBadFunction
Ok

>>>>>> TestWithInt
>>> TestWithInt:testSuperFunction
Ok
>>> TestWithInt:testBadFunction
Ok
>>> TestWithInt:testThatFails
use_luaunit2.lua:44: expected: 'hop', actual: 'bof'
Failed

Success : 60% - 3 / 5

You can also run tests individually:

shell $ lua use_luaunit2.lua TestWithInt:testSuperFunction
>>>>>> TestWithInt
>>> TestWithInt:testSuperFunction
Ok

Success : 100% - 1 / 1


shell $ lua use_luaunit2.lua TestWithFloat
>>>>>> TestWithFloat
>>> TestWithFloat:testSuperFunction
use_luaunit2.lua:66: expected: 3.2, actual: 3
Failed
>>> TestWithFloat:testBadFunction
Ok

Success : 50% - 1 / 2

See Also


FindPage · RecentChanges · preferences
edit · history
Last edited January 29, 2008 1:53 am GMT (diff)