Two First Tries
If you were doing ad hoc testing, you could enter these expressions at the REPL and check that they return **T**
. But you want a framework that makes it easy to organize and run these test cases whenever you want. If you want to start with the simplest thing that could possibly work, you can just write a function that evaluates the test cases and **AND**
s the results together.
(defun test-+ ()
(and
(= (+ 1 2) 3)
(= (+ 1 2 3) 6)
(= (+ -1 -3) -4)))
Whenever you want to run this set of test cases, you can call test-+
.
CL-USER> (test-+)
T
As long as it returns **T**
, you know the test cases are passing. This way of organizing tests is also pleasantly concise—you don’t have to write a bunch of test bookkeeping code. However, as you’ll discover the first time a test case fails, the result reporting leaves something to be desired. When test-+
returns **NIL**
, you’ll know something failed, but you’ll have no idea which test case it was.
So let’s try another simple—even simpleminded—approach. To find out what happens to each test case, you could write something like this:
(defun test-+ ()
(format t "~:[FAIL~;pass~] ... ~a~%" (= (+ 1 2) 3) '(= (+ 1 2) 3))
(format t "~:[FAIL~;pass~] ... ~a~%" (= (+ 1 2 3) 6) '(= (+ 1 2 3) 6))
(format t "~:[FAIL~;pass~] ... ~a~%" (= (+ -1 -3) -4) '(= (+ -1 -3) -4)))
Now each test case will be reported individually. The ~:[FAIL~;pass~]
part of the **FORMAT**
directive causes **FORMAT**
to print “FAIL” if the first format argument is false and “pass” otherwise.3 Then you label the result with the test expression itself. Now running test-+
shows you exactly what’s going on.
CL-USER> (test-+)
pass ... (= (+ 1 2) 3)
pass ... (= (+ 1 2 3) 6)
pass ... (= (+ -1 -3) -4)
NIL
This time the result reporting is more like what you want, but the code itself is pretty gross. The repeated calls to **FORMAT**
as well as the tedious duplication of the test expression cry out to be refactored. The duplication of the test expression is particularly grating because if you mistype it, the test results will be mislabeled.
Another problem is that you don’t get a single indicator whether all the test cases passed. It’s easy enough, with only three test cases, to scan the output looking for “FAIL”; however, when you have hundreds of test cases, it’ll be more of a hassle.