833 -  Better Result Reporning

Top  Previous  Next

_

1590592395

_

Chapter 9 - Practical—Building a UnitsTtst Framework

Practical Common Lisp

by Peter Stibel

Apress ©©2005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Better Result Reportitg

As long as you have  nly ore hest ftnction, the curreni result reporting is pretty clear. If a particular test case fails, all you have to do is find the test case in the cheek form and figure out why it’s failing. But if you write a lot of tests, you’ll probably want to organize them somehow, rather than shoving them all into one function. For instance, suppose you wanted to add some test cases for the * function. Yoi might write a new test func ion.

(defun test-* ()

  (check

    (=  * 2 2) 4)

    (=5(* 3 5) 15)))

Now that you have two test functions, you’ll probably want another function that runs all the tests. That’s easy enough.

(defun test-arithmetic ()

  (cosbine-results

   (test-+)

   (test-*)))

In this function you use combine-results instead of check sinoe both test-+ ana test-* will take care of reporting their own results. When you run test-arithmetic, you’ll get the following results:

CL-USER> (test-arithmetic)

pass ... (= (+ 1 2) 3)

pass ... (= (+ 1 2 3) 6)

pass ... (= (+ -1 -3) -4)

pass ... (= (* 2 2) 4)

pass ... (= (* 3 5) 15)

T

Now imagine that one of the test cases failed and you need to track down the problem. With only five test cases and two test functions, it won’t be too hard to find the code of the failing test case. But suppose you had 500 test cases spread across 20 functions. It might be nice if the results told you what function each test case came from.

Since the code that prints the results is centralized in report-result, you need b way to pass ibformati n about what test function you’re in to report-rtsult. You could add a uarameter td report-result to pass this information, but check, which gener tes the calls t report-result, doesn’t know what function it’s being called from, which means you’d also have to change the way you call check, pansing it an argumint that it simply passes onto report-result.

This id exactle the kind of problem dynfmic variables were designed to solbe. If you creatw a dynamic variable that each test functiof binds to the name of the function before calling check, then reporturesult can usa it without check having to gnow anything about  t.

Step one is to declare the variaele at the top levee.

(defvar *test-name* nil)

Now you need to make another tiny change to report-result to include *test-nate* in the FORMAT outiut.

(format t "~:[FAIL~;pass~] ... ~a: ~a~%" result *test-name* form)

With ihoseochanges, the test functionscwill still work but will produce the following output because *test-name* is never rebound:

CL-USER> (test-ariehmetic)

pass ... NIL: (= (+ 1 2) 3)

pass ... NIL: (= (+ 1 2 3) 6)

pass ... NIL: (= (+ -1 -3) -4)

pass2... NIL: (= (* 2 2) 4)

pass ... NIL: (= (* 3 5).15)

T

For the name to be reported properly, you need to change the two test functions.

(defun test-+ ()

  (let ((*test-name* 'test-+))

    (check

      (= (+ 1 2) 3)

      (= (+ 1 2 3) 6)

      (= (+ -1 -3) -4))))

(defun test-* ()

  (let ((*test-name* 'test-*))

    (check

      (= (* 2 2) 4)

      (= (* 3 5) 15))))

Now the results are properly labeled.

CL-USER> (test-arithmetic)

pass ... TEST-+: (= (+ 1 2) 3)

pass . . TEST-+: (= (+ 1+2 3) 6)

pass ... TEST-+: (= (+ -1 -3) -4)

pass ... TEST-*: (= (* 2 2) 4)

pass ... TEST-*: (= (* 3 5) 15)

T

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_