moved old instructions for external packages to top-level in preparation for nuking...
[CommonLispStat.git] / external / lift.darcs / website / source / user-guide.md
blobb0ee84bb055f26348e359eb3daa9dc7aafbb2d03
1 {include resources/ug-header.md}
2 {set-property title "LIFT User's Guide"}
3 {set-property style-sheet user-guide}
4 {set-property docs-package lift}
6 # LIFT User's Guide
8 # Table of Contents 
10 {table-of-contents :start 2 :depth 3}
12 ## Introduction
14 The LIsp Framework for Testing (LIFT) is a unit and system test tool for LISP. 
15 Though inspired by [SUnit][] and [JUnit][], it's built with Lisp in mind. 
16 In LIFT, [testcases][] are organized into hierarchical [testsuites][] each of 
17 which can have its own [fixture][]. When run, a testcase can succeed, fail, 
18 or error. LIFT supports randomized testing, benchmarking, profiling, and reporting.
20  [testcases]> glossary A test-case is the smallest unit of testing.
21  [testsuites]> glossary A testsuite is a group of tests plus their environment plus local variables and configuration settings. 
22  [fixture]> glossary The environment in which a test-case runs. This includes code for both setup and teardown.
24 ## Overview : our first testsuite
26 LIFT supports interactive testing so imagine that we type each of the following forms into a file and evaluate them as we go. 
28     (in-package #:common-lisp-user)
29     (use-package :lift)
31 First, we define an empty testsuite. [deftestsuite][] is like defclass
32 so here we define a testsuite with no super-testsuites and
33 no slots.
34     
35     > (deftestsuite lift-examples-1 () ())
36     ==> #<lift-examples-1: no tests defined>
38 Add a test-case to our new suite. Since we don't specify a testsuite or a test name, 
39 LIFT will add this to the most recently defined testsuite 
40 and name it for us.
42     > (addtest (ensure-same (+ 1 1) 2))
43     ==> #<Test passed>
45 Add another test using ensure-error
46 Here we specify the testsuite and the name.
48     > (addtest (lift-examples-1)  ; the testsuite name
49          div-by-zero              ; the testcase name
50        (ensure-error (let ((x 0)) (/ x))))
51     ==> #<Test passed>
53 Though it works, [ensure-error][] is a bit heavy-handed in this case. We can use
54 [ensure-condition][] to check that we get exactly the right _kind_ of error.
56     > (addtest (lift-examples-1)
57         div-by-zero
58        (ensure-condition division-by-zero 
59            (let ((x 0)) (/ x))))
60     ==> #<Test passed>
62 Notice that because we named the testcase `div-by-zero`, LIFT will replace the previous definition with this one. If you don't name your tests, LIFT cannot distinguish between correcting an already defined test and creating a new one.
64 Now, let's us [run-tests][] to run all our tests.
65 Unless you tell it otherwise, [run-tests][] runs all the test-cases
66 of the most recently touched testsuite{footnote "By 'touched', I mean the last testsuite in which a testcase was run."}. Here, thats
67 lift-example-1.
69     > (run-tests)
70     ==> #<Results for lift-examples-1 [2 Successful tests]>
72 As you saw above, if you don't supply a test-case name, LIFT will give it one. This works for quick interactive testing but makes it hard to find a problem when running regression tests. It's a much better practice to give every test-case a name -- it also makes the testsuite self documenting. 
74 Here is a test-case that fails because floating point math isn't exact.
76     > (addtest (lift-examples-1)
77        floating-point-math
78        (ensure-same (+ 1.23 1.456) 2.686))
79     ==> #<Test failed>
81 Hmmm, what happened? Lift returns a [test-result][] object so we can look at it to understand what went wrong. Let's [describe][] it:
83     > (describe *)
84     Test Report for lift-examples-1: 1 test run, 1 Failure.
85     
86     Failure: lift-examples-1 : floating-point-math
87       Condition: Ensure-same: 2.6859999 is not equal to 2.686
88       Code     : ((ensure-same (+ 1.23 1.456) 2.686))
90 We try again using the function `almost=` for the test of [ensure-same][]
92     > (addtest (lift-examples-1)
93         floating-point-math
94         (ensure-same (+ 1.23 1.456) 2.686 :test 'almost=))
95     ==> #<Error during testing>
97 Whoopts, we forgot to write `almost=`! Here's a simple (though not
98 very efficient) version
100     > (defun almost= (a b)
101        (< (abs (- a b)) 0.000001))
102     ==> almost=
104 Like `run-tests`, [run-test][] runs the most recently touched test-case.
106     > (run-test)
107     ==> #<lift-examples-1.lift-examples-1 passed>
109 The examples above cover most of LIFT's basics: 
111 * Use [deftestsuite][] and [addtest][] to define testsuites and test-cases.
112 * In a testcase, use members of the ensure family of macros (like [ensure][], [ensure-same][], and [ensure-condition][]) to specify what is supposed to happen
113 * Run tests interactively by evaluating them or by calling [run-test][] or [run-tests][]
115 In what follows, we'll explore LIFT in more depth by looking at test hierarchies and fixtures, randomized testing, and using LIFT for benchmarking and profiling.
117 ## Defining testsuites and adding testcases.
119 The [deftestsuite][] macro defines or redefines a testsuite. Testsuites are CLOS classes and deftestsuite looks a lot like defclass.
121     (deftestsuite name (supersuite*)
122         (slotspec*)
123         options*)
125 The list of supersuites lets you organize tests into a hierarchy. This can be useful both to share fixtures (i.e., setup and tearcode code) and to organize your testing: different parts of the hierarchy can test different parts of your software. The slotspecs are similar to slotspecs in defclass but with a twist: deftestsuite automatically adds an initarg and accessor for each spec{footnote "Though they once did, the slotspecs don't really define slots for the class internally anymore. LIFT keeps track of slot values through a different (slower but more flexible) mechanism."}. You can specify an initial value using a pair rather than needing to specify an initform and these value can use the values of previously defined slots (as if they were being bound in a let* form). Finally, you'll also see below that slot values are immediately available with the body of a test method. These two features make writing tests very simple.
127     > (deftestsuite test-slots ()
128         ((a 1) (b 2) (c (+ a b)))
129         (:test ((ensure-same (+ a b) c))))
130     Start: test-slots
131     #<Results for test-slots [1 Successful test]>
133 The example above also shows that you can define tests directly in the deftestsuite form.  This is really handy for unit testing where you don't want the boilerplate to get in the way of the tests! Here is another, more complex example:
135     > (deftestsuite test-leap-year-p ()
136        ()
137        ;; Use :tests to define a list of tests
138        (:tests
139         ((ensure (leap-year-p 1904)))
140         ;; we give this one a name
141         (div-by-four (ensure (leap-year-p 2000)))
142         ((ensure (leap-year-p 1996))))
143        ;; use :test to define one test at a time
144        (:test ((ensure-null (leap-year-p 1900))))
145        (:test ((ensure-null (leap-year-p 1997)))))
147     ;; let's see what we've done
148     > (print-tests :start-at 'test-leap-year-p)
149     test-leap-year-p (5)
150       TEST-1
151       div-by-four
152       TEST-3
153       TEST-4
154       TEST-5
156 So far, our tests have not required any setup or teardown. Let's next look at at a few tests that do. The first example is from the [ASDF-Install][] testsuite. It uses its fixtures setup to make sure that the working directory is empty (so that it is ensured of installing into a clean system).{footnote "We'll talk about the :dynamic-variables clause in more detail below."}
158     (deftestsuite test-asdf-install-basic-installation (test-asdf-install) 
159       ()
160       (:dynamic-variables 
161        (*verify-gpg-signatures* t))
162       (:setup 
163        (delete-directory-and-files *working-directory* 
164            :if-does-not-exist :ignore)))
166 This next testsuite is from [Log5][log5]. 
167 Though the details aren't important, you can be assured that LIFT will run the setup before every test-case and the teardown after every test-case (even if there is an error).  
169     (deftestsuite test-stream-sender-with-stream (test-stream-sender)
170      (sender-name
171       string-stream
172       (sender nil))
173      (:setup
174       (setf sender-name (gensym)
175          string-stream (make-string-output-stream)))   
176      (:teardown (stop-sender-fn sender-name :warn-if-not-found-p nil))
177      :equality-test #'string-equal)
180 #### Deftestsuite options and arguments
182 We've already seen two other clauses that deftestsuite supports (:dynamic-variables and :equality-test). Here is the complete list:
184 * dynamic-variables - specifies how to initialize dynamic-variables within a testsuite
185 * documentation - used, of all things, for documentation
186 * equality-test - specifies the default equality-test used by ensure-same and ensure-different. See [\*lift-equality-test\*][*lift-equality-test*]
187 * export-p - if true, the testsuite name will be exported
188 * export-slots - if true, all of the testsuite slots will be exported. It can also be a list of slot names to export
189 * function - defines a local test function (think of flet or labels)
190 * random-instance - tells LIFT how to make random examples of things for this suite
191 * run-setup - tells LIFT when to run setup.
192 * setup - code for test setup
193 * teardown - code for testsuite teardown
194 * test - defines a single test
195 * tests - defines several tests
196 * timeout - how long can each test take
198 Many of these are self-explanatory. We'll discuss  :dynamic-variables, :equality-test, :function, :run-setup and :timeout here and look at :random-instance below when we talk about random-testing. 
200 ##### Dynamic-variables
202 It is often the case that you'll want some dynamic variable bound around the body of all of your tests. This is hard to do because LIFT doesn't expose its inner mechanisms for easy access.{footnote "At least, it doesn't expose them yet... One long range plan is to do a better job of building a sort of test metaobject protocol that would make it easier to extend LIFT in new and exciting ways."} The :dynamic-variables clause lets you specify a list of variables and bindings that LIFT will setup for each testcase.
204 ##### Equality-test
206 This is used to specify the default equality-test used by [ensure-same][] for test-cases in this suite and any suites that inherit from it. Though you can use the special variable [*lift-equality-test*][] to set test, it usually better to exercise control at the testsuite level. This is especially handy when, for example, you are testing numeric functions and want to avoid having to specify the test for every `ensure-same`.
208 ##### Function
210 Let the Common Lisp forms `flet`, `labels`, and `macrolet`, [deftestsuite][]'s `function` clause lets you define functions that are local to a particular testsuite (and its descendants). There are two good reasons to use `:function`: it provides good internal documentation and structure _and_ you can use the testsuite's local variables without without any fuss or bother. Here is an example:
212     (deftestsuite test-size (api-tests)
213         (last-count db)
214      (:function
215         (check-size (expected)
216             (ensure (>= (size) last-count))
217             (setf last-count (size))
218             (ensure-same (size) (count-slowly db))
219             (ensure-same (size) expected)))
220      (:setup
221         (setf db (open-data "bar" :if-exists :supersede)))
223 The `check-size` function will not conflict with any other check-size functions (from other tests or any of Lisp's other namespaces). Secondly, the references to `last-count` and `db` will automatically refer to the testsuite's variables.
225 ##### Run-setup
227 LIFT's usual behavior is to run a testsuite's `setup` and `teardown` code around every single test-case. This provides the best isolation and makes it easy to think about a test-case by itself. If test setup takes a _long_ time or if you want to break a complex test into a number of stages, then LIFT's usual behavior will just get in the way. The `run-setup` clause lets you control when `setup` (and `teardown`) occur. It can take on one of the following values:
229 * :once-per-test-case or t (the default) - run `setup` and `teardown` around every testcase
230 * :once-per-suite - run `setup` for the first test-case of a testsuite and run `teardown` after the last test-case.
231 * :never or nil
233 ##### Timeout
235 Things go wrong (that is, after all, part of why we write tests!). The `timeout` clause lets you tell LIFT that if test-case hasn't completed within a certain number of seconds, then you want LIFT to complete the test with an error. 
237 ### LIFT and Random testing
239 To be written.
241 ### Benchmarking with LIFT
243 To be written.
245 ### Reporting
247 To be written.
249 <div class='reference'>
250     
251 ## Reference
253 ### Defining Tests
255 {docs deftestsuite macro}
256 {docs addtest macro}
258 ### How to test for something
260 The following macros can be used outside of LIFT where they will function very much like `assert`. When used in the body of an `addtest` or `deftestsuite` form, however, they will record test failures instead of signaling one themselves.{footnote "Random testing adds a few additional `ensure` variants like [ensure-random-cases][]."}
262 {docs ensure macro}
263 {docs ensure-null macro}
264 {docs ensure-same macro}
265 {docs ensure-different macro}
266 {docs ensure-condition macro}
267 {docs ensure-warning macro}
268 {docs ensure-error macro}
269 {docs ensure-no-warning}
270 {docs ensure-cases macro}
272 ### Running tests 
274 {docs run-test function}
275 {docs run-tests function}
276 {docs lift-result}
277 {docs lift-property}
278 {docs *test-result* variable}
280 ### Configuring LIFT
282 Many of the variables below are used as the default values
283 when calling [run-test][] or [run-tests][] or when interactively defining new tests and testsuites.
285 #### Variables that control how LIFT runs tests
287 {docs *test-ignore-warnings?* variable}
288 {docs *test-break-on-errors?* variable}
289 {docs *test-break-on-failures?* variable}
290 {docs *test-maximum-time* variable}
291 {docs *test-print-testsuite-names* variable}
292 {docs *test-print-test-case-names* variable}
293 {docs *lift-equality-test* variable}
294 {docs *lift-debug-output* variable}
295 {docs *lift-dribble-pathname* variable}
296 {docs *lift-report-pathname* variable}
298 #### Variables that change how LIFT displays information
300 {docs *test-describe-if-not-successful?* variable}
301 {docs *test-evaluate-when-defined?* variable}
302 {docs *test-print-length* variable}
303 {docs *test-print-level* variable}
304 {docs *test-print-when-defined?* variable}
305 {docs *test-show-expected-p* variable}
306 {docs *test-show-details-p* variable}
307 {docs *test-show-code-p* variable}
309 ### Introspection
311 {docs print-tests}
312 {docs map-testsuites}
313 {docs testsuites}
314 {docs testsuite-tests}
315 {docs find-testsuite}
316 {docs last-test-status}
317 {docs suite-tested-p}
318 {docs testsuite-p}
319 {docs failures}
320 {docs errors}
321 {docs expected-failures}
322 {docs expected-errors}
324 ### Random testing
326 {docs ensure-random-cases}
327 {docs ensure-random-cases+}
328 {docs random-instance-for-suite}
330 {docs ensure-random-cases-failure}
332 {docs defrandom-instance}
333 {docs random-element}
334 {docs random-number}
335 {docs an-integer}
336 {docs a-double-float}
337 {docs a-single-float}
338 {docs a-symbol}
340 ### Benchmarking and Profiling
342 {docs measure-time}
343 {docs measure-conses}
345 ### Miscellaneous 
347 {docs test-mixin}
348 {docs *current-test*}
350 </div>
352 ## Indices
354 ### Index of Functions
356 {docs-index function}
358 ### Index of variables
360 {docs-index variable}
362 ### Index of Macros
364 {docs-index macro}
366 ### Full symbol index
368 {docs-index :all}
370 <hr>
372 #### Glossary
374 {glossary}
377 #### Footnotes
379 {footnotes}
381 {include resources/ug-footer.md}