Home

Awesome

New Project Steward Required!

This project needs a new maintainer or someone to continue taking it forward. I put a lot of effort and passion to deliver not just a functional but also a beautifully designed and written piece of code. Unfortunately other commitments have crept up over the years, thus I hope someone just as passionate can take over.

CLUnit

CLUnit is a Common Lisp unit testing framework. It is designed to be easy to use so that you can quickly start testing.

Author: Tapiwa Gutu

CLUnit provides a rich set of features aimed at improving your unit testing experience:

Check out the comprehensive CLUnit Tutorial.

Example

(ql:quickload "clunit")
(use-package :clunit)

;; Test suite for all number operation tests.
(defsuite NumberSuite ())
  
;; Test suite for floating point operations
(defsuite FloatSuite (NumberSuite))
  
(defsuite IntegerSuite (NumberSuite))
    
;; Define a test called TEST-INT1
(deftest test-int1 (IntegerSuite)
    (assert-true  (= 1 1))
    (assert-equalp 4 (+ 2 2)))

;; Define a test called TEST-FLOAT1
(deftest test-float1 (FloatSuite)
    (assert-true (= 1.0 -1.0))
    (assert-equalp 4.0 (+ 2.0 2.0)))

(print (run-suite 'NumberSuite))

which produces the output:

PROGRESS:
=========

    NUMBERSUITE: (Test Suite)

        INTEGERSUITE: (Test Suite)
            TEST-INT1: ..

        FLOATSUITE: (Test Suite)
            TEST-FLOAT1: F.

FAILURE DETAILS:
================

    NUMBERSUITE -> FLOATSUITE: (Test Suite)
        TEST-FLOAT1: Expression: (= 1.0 -1.0)
                     Expected: T
                     Returned: NIL


SUMMARY:
========
    Test functions:
        Executed: 2
        Skipped:  0

    Tested 4 assertions.
        Passed: 3/4 ( 75.0%)
        Failed: 1/4 ( 25.0%) 

(if you are entering forms in the REPL, the print form is not usually needed).

Tests and assertions

Each test, like test-int1 in the above example, can contain a number of assertions, given in the table below:

AssertionDescription
assert-true EXPRESSIONPasses if the expression EXPRESSION is not NIL
assert-false EXPRESSIONPasses if EXPRESSION is NIL
assert-eq VALUE EXPRESSIONPasses if (EQ VALUE EXPRESSION) returns true
assert-eql VALUE EXPRESSIONPasses if (EQL VALUE EXPRESSION) returns true
assert-equal VALUE EXPRESSIONPasses if (EQUAL VALUE EXPRESSION) returns true
assert-equalp VALUE EXPRESSIONPasses if (EQUALP VALUE EXPRESSION) returns true
assert-equality TEST VALUE EXPRESSIONPasses if (FUNCALL TEST VALUE EXPRESSION) returns true
assert-equality* VALUE EXPRESSIONPasses if (FUNCALL \*clunit-equality-test\* VALUE EXPRESSION) returns true. By default clunit-equality-test is EQUALP
assert-expands EXPANSION EXPRESSIONTests macro expansion, passes if (EQUALP EXPANSION (MACROEXPAND-1 EXPRESSION)) is true
assert-condition CONDITION EXPRESSIONPasses if EXPRESSION signals CONDITION
assert-fails FORMAT-STRINGForce test to fail, giving a format string for the message

All of these tests take optional forms, which are evaluated and printed if the test fails. These can be used to provide test diagnostics or documentation. For example


(deftest test-suiteless ()
    (let ((a 1) (b 2) (c 3))
        (assert-true (= a b c) "This assertion is meant to fail." a b c )))

(run-test 'test-suiteless :report-progress nil)

produces the output:

FAILURE DETAILS:
================
    TEST-SUITELESS: Expression: (= A B C)
                    Expected: T
                    Returned: NIL
                    This assertion is meant to fail.
                    A => 1
                    B => 2
                    C => 3

SUMMARY:
========
    Test functions:
        Executed: 1
        Skipped:  0

    Tested 1 assertion.
        Passed: 0/1 (  0.0%)
        Failed: 1/1 (100.0%)
        Errors: 0/1 (  0.0%)

(if not in a REPL, you may have to print the return value of run-test).