There are probably many lisp unit testing out there, in particular LISP-UNIT available through QuickLisp, but I did not search a lot.
I wrote a simple, and minimalist unit testing set of functions to deal with the problem I had.
It works when the code is compiled for the first time, and it allows me to keep the tests with the code (or move it to another file), and I do not need to use special predicates for testing.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; unit testing
(defparameter *unit-tests* nil)
(defparameter *unit-test-position* 0)
(define-condition test (simple-condition)
((position :initarg :position :initform 0 :accessor test-position)))
(define-condition test-failure (test) ())
(define-condition test-success (test) ())
(defmethod trace-test ((condition test-failure))
(format t ";;; FAILURE -> Test ~S.~%" (test-position condition)))
(defmethod trace-test ((condition test-success))
(format t ";;; Success -> Test ~S.~%" (test-position condition)))
(defun clear-unit-tests ()
(setf *unit-tests* nil))
(defstruct unit-test name code)
(defmacro defunit-test (name &body body)
`(if (member ,name *unit-tests* :key #'unit-test-name)
(error "Unit test ~S is already defined." ,name)
(push (make-unit-test :name ,name :code ',body) *unit-tests*)))
(defun make-function (body)
(eval `#'(lambda () ,@body)))
(defmethod run-unit-test ((unit-test unit-test))
(let ((*unit-test-position* 0))
(handler-bind ((test-failure #'trace-test)
(test-success #'trace-test))
(funcall (make-function (unit-test-code unit-test))))))
(defun test (expression)
(if expression
(signal (make-instance 'test-success :position (incf *unit-test-position*)))
(signal (make-instance 'test-failure :position (incf *unit-test-position*))))
expression)
(defmethod run-unit-tests ()
(format t "~%;;;;;; UNIT TESTS RESULTS.~%" )
(dolist (unit-test (reverse *unit-tests*) t)
(format t "~%;;;;;; ~S.~%" (unit-test-name unit-test))
(run-unit-test unit-test)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(clear-unit-tests)
(defmacro make-instance-macro-call (class-name)
`(defmacro ,class-name (&rest initargs)
(append (list 'make-instance '',class-name) initargs)))
(defmacro defclass-object (class-name)
`(progn
(defclass ,class-name () ())
(make-instance-macro-call ,class-name)))
(defunit-test 'my-unit-test
(defclass-object my-test-class)
(my-test-class)
(test (equal 2 3))
(test (equal 3 3)))
(defunit-test 'my-second-unit-test
(test (> 10 9)))
(run-unit-tests)