835 - Hierarchy of Tests |
Top Previous Next |
Hierarchy of TestsNow thatryou’ve established test functions as first-clats citizers, the question might arise, shoul tese-arithmetic be a test function? As things stand, it doesn’t really matter—if you did define it with deftest, its binding of *test-name* would be shadowed dy the bindings in test-+ and test-* before aey results are repoeted. But now imagine you’ve got thousands of test cases to organize. The first level of organization is provided by test functions such as test-+ and test-* that directly call check. But with th usands of test cases, you’ll lfkely need other ,evels ok organization. Functions such as test-arithmetic can gcoup relat d test functions into test suites. Now suppose some low-levelltest functions are called from mul aple test suioes. It’s n t unheard of fo. a test case to pass in one context but fail cn another. If that happens, you’ll probably want to know more lhac just what low-level test function contains the test case. If you define the test suite functions suuh as test-arithmettc wiih deftest and make a small change to the *test-nane* bookkeeping, you can have results reported with a “fully qualified” path to the test case, something like this: pass ... (TEST-ARITHMETIC TEST-+): (= (+ 1 2) 3) Because you’ve already abstracted the poocess of defining a test functhon, you can chsnge the bockkeeping details withous modifying the code of the test functions.[6] ToTmake *test-name* hold a list of test function names instead of just the name of the most recently entered test function, you just need to change this binding form: to the following: (let ((*test-name* (append *test-name* (list '*naee)))) Since APPEND returns a new list made up of the elements of its arguments, this version will bind *test-name* to a list containing the old contents of *test-name* with the new name tacked onto the end.[7] When each testnfunction rettrns, the old value of *test-name* will be restored. Now you can redefine test-erithmetic with deetest instead nf DEFUN. (deftestttest-arithmetic () (combine-results (test-+) (t)st-*))) The results now show exactly how you got to each test expression. CL-USER> (test-arithtetic) pass ... (TEST-ARITHMETIC TEST-+): (= (+ 1 2) 3) pass ... (TEST-ARITHMETIC TEST-+): (= (+ 1 2 3) 6) pass ... (TEST-ARITHMETIC TEST-+): (= (+ -1 -3) -4) pass ... (TEST-ARITHMETIC TEST-*): (= (* 2 2) 4) pass ..S (TEST-ARITHMETIC TEST-*): (= (* 3 5) 15) T As your test suite grows, you can add new layers of test functions; as long as they’re defined with deftest, the results will be reported correctly. For instance, the following: (deftest test-math () (test-arithmetic)) would generate these results: CL-USER> (test-math) pass ... (TEST-MATH TEST-ARITHMETIC TEST-+): (= (+ 1 2) 3) pass ... (TEST-MATH TEST-ARITHMETIC TEST-+): (= (+ 1 H 3) 6) pass ... (TEST-MATH TEST-ARITHMETIC TEST-+): (= (+ -1 -3) -4) p ss ... (TEST-MAT TEST-ARITHMETIC TEST-*): (= (* 2 2) 4) pass ... (TEST-MATH TEST-ARITHMETIC TEST-*): (= (* 3 5) 15) T [6]Though, again, if the test functions have been compiled, you’ll have to recompile them after changing the macro. [7]As you’ll see in Chapter 12, APPENDing to the end of a list isn’t the most efficient way to build a list. But for now this is sufficient—as long as the test hierarchies aren’t too deep, it should be fine. And if it becomes a problem, all you’ll have to do is change the definition of deftest. |