Add in TODO note
[fiveam.git] / docs / manual.txt
1 = FiveAM Manual =
2 Marco Baringer <mb@bese.it>
3 Fall/Winter 2012
4 :Author Initials: MB
5 :toc:
6 :icons:
7 :numbered:
8 :website: http://common-lisp.net/project/fiveam
9 :stylesheet: fiveam.css
10 :linkcss:
11
12 == Introduction ==
13
14 === The Super Brief Introduction ===
15
16 FiveAM is a testing framework. See the xref:API_REFERENCE[api] for
17 details.
18
19 === An Ever So Slightly Longer Introduction ===
20
21 You use define some xref:TESTS[tests] (using
22 xref:OP_DEF-TEST[`def-test`]), each of which consists of some
23 xref:CHECKS[checks] (with xref:OP_IS[`is`] and friends) which can pass
24 or fail; you xref:RUNNING_TESTS[run] some tests (using
25 xref:OP_RUN-EPOINT-[run!] and friends) and you look at the results
26 (probably using xref:OP_RUN-EPOINT-[run!] again). Rinse, lather,
27 repeat.
28
29 === The Real Introduction ===
30
31 FiveAM is a testing framework, this is a rather vague concept, so
32 before talking about how to use FiveAM it's worth knowing what task(s)
33 FiveAM was built to do and, in particular, which styles of testing
34 FiveAM was designed to facilitate:
35
36 `test driven development`:: sometimes you know what you're trying to
37   do (lucky you) and you can figure out what your code should do
38   before you've written the code itself. The idea here is that you
39   write a bunch of tests and when all these test pass your code is
40   done.
41
42 `interactive testing`:: sometimes as you're writing code you'll see
43   certain constraints that your code has to meet. For example you'll
44   realize there's a specific border case your code, which you're
45   probably not even done writing, has to deal with. In this work flow
46   you'll write code and tests more or less simultaneously and by the
47   time you're satisfied that your code does what it should you'll have
48   a set of tests which prove that it does what you think it does.
49
50 `regression testing`:: sometimes you're pretty confident, just by
51   looking at the code, that your program does what it should, but you
52   want an automatic way to make sure that it continues to do what it
53   does even if (when) you change other parts of the code.
54
55 [NOTE]
56 There's also `beaviour driven development`. this works under
57 the assumption that you can write tests in a natural-ish lanugage and
58 they'll be easier to maintain than tests writen in code (have we
59 learned nothing from cobol?). FiveAM does not, in its current
60 implementation, support link:http://cukes.info/[cucumber] like
61 behaviour driven development. patches welcome (they'll get laughed at
62 at first, but they'll get applied, and then they'll get used, and then
63 they'll be an essential part of fiveam itself...)
64
65 === Words ===
66
67 Since there are far many more testing frameworks than there are words
68 for talking about testing frameworks, the same words end up meaning
69 different things in different frameworks. Just to be clear, here are
70 the words fiveam uses:
71
72 `check`:: a single expression which has an expected value.
73
74 `test`:: a set of checks which we want to always run together.
75
76 `suite`:: a group of tests we often want to run all at once.
77
78 [[TESTS]]
79 == Tests ==
80
81 Tests are created with the xref:OP_DEF-TEST[`def-test`] macro and
82 consist of:
83
84 A name::
85
86 Because everything deserves a name. Names in FiveAM are symbols (or
87 anything that can be sensibly put in an `eql` hash table) and they are
88 used both to select which test to run (as arguments to `run!` and
89 family) and when reporting test failures.
90
91 A body::
92
93 Every test has a function which is the actual code that gets executed
94 when the test is run. This code, whatever it is, will, bugs aside,
95 xref:CHECKS[create a set of test result objects] (failures, successes
96 and skips) and store these in a few dynamic variables (you don't need
97 to worry about those).
98
99 The body is actually the only real part of the test, everything else
100 is administrativia. Sometimes usefel administrativia, but none the
101 less overhead.
102
103 A suite::
104
105 Generally speaking you'll have so many tests that you'll not want to
106 run them all every single time you need to run one of them (automated
107 regression testing is another use case). Tests can be grouped into
108 suites, and suites can also be grouped into suites, and suites have
109 names, so by specfying the name of a suite we only run those tests
110 that are a part of that suite.
111 +
112 Unless otherwise specified tests add themselves to the xref:THE_CURRENT_SUITE[current suite].
113
114 There are two other properties, also set via parameters to
115 xref:OP_DEF-TEST[`def-test`], which influence how the tests are
116 run:
117
118 When to compile the test::
119
120 Often enough, when working with lisp macros especially, it's useful to
121 delay compilation of the test's body until the test is run. A useful
122 side effect of this delay is that the code will be recompiled every
123 time its run, so if the macro definition has changed that will be
124 picked up at the next run of the test. While this is the default mode
125 of operation for FiveAM it can be turned off and tests will be
126 compiled at the 'normal' time (when the enclosing def-test form is
127 compiled).
128
129 Whether to run the test at all::
130
131 Sometimes, but far less often than the designer of FiveAM expected,
132 it's useful to run a test only when some other test passes. The
133 assumption being that if the lower level tests have failed there's no
134 point in cluttering up the output by running the higher level tests as
135 well.
136 +
137 YMMV. (i got really bad mileage out of this feature)
138
139 [[CHECKS]]
140 == Checks ==
141
142 At the heart of every test is something which compares the result of
143 some code to some expected value, in FiveAM these are called
144 checks. All checks in FiveAM do something, exactly what depends on the
145 check, and then either:
146
147 . generate a "this check passed" result
148
149 . generate a "this check failed" result and a corresponding failure
150   description message.
151
152 . generate a "for some reason this check was skipped" result.
153
154 All checks take, as an optional argument, so called "reason format
155 control arguments." Should the check fail (or be skipped) these
156 arguments will be passed to format, via something like `(curry
157 #'format nil)`, and the result will be used as the
158 explanation/description of the failure.
159
160 When it comes to the actual check functions themeselves, there are
161 three basic kinds:
162
163 . xref:CHECKING_RETURN_VALUES[those that take a value and compare it
164 to another value]
165
166 . xref:CHECKING_CONTROL_FLOW[those that make sure the program's
167 execution takes, or does not take, a certain path]
168
169 . xref:ARBITRARY_CHECK_RESULTS[those that just force a success or
170 failure to be recorded].
171
172 [[CHECKING_RETURN_VALUES]]
173 === Checking return values ===
174
175 xref:OP_IS[`IS`], xref:OP_IS-TRUE[`IS-TRUE`],
176 xref:OP_IS[`IS-FALSE`] will take one form and compare its return
177 value to some known value (the so called expected vaule) and report an
178 error if these two are not equal.
179
180 --------------------------------
181 ;; Pass if (+ 2 2) is = to 5
182 (is (= 5 (+ 2 2)))
183 ;; Pass if (zerop 0) is not-NIL
184 (is-true (zerop 0))
185 ;; Pass if (zerop 1) is NIL
186 (is-false (zerop 1))
187 --------------------------------
188
189 Often enough we want to test a set of expected values against a set of
190 test values using the same operator. If, for example, we were
191 implementing a string formatting functions, then `IS-EVERY` provides a
192 concise way to line up N different inputs along with their expected
193 outputs. For example, let's say we were testing `cl:+`, we could setup
194 a list of tests like this:
195
196 --------------------------------
197 (is-every #'= (5 (+ 2 2))
198               (0 (+ -1 1))
199               (-1 (+ -1 0))
200               (1 (+ 0 1))
201               (1 (+ 1 0)))
202 --------------------------------
203
204 We'd do this instead of writing out 5 seperate `IS` or `IS-TRUE`
205 checks.
206
207 [[CHECKING_CONTROL_FLOW]]
208 === Checking control flow ===
209
210 xref:OP_SIGNALS[`SIGNALS`] and xref:OP_FINISHES[`FINISHES`] create
211 pass/fail results depending on whether their body code did or did not
212 terminat normally.
213
214 Both of these checks assume that there is a single block of code and
215 it either runs to completion or it doesn't. Sometimes though the logic
216 is more complex and you can't easily represent it as a single progn
217 with a flag at the end. See xref:ARBITRARY_CHECK_RESULTS[below].
218
219 [[ARBITRARY_CHECK_RESULTS]]
220 === Recording arbitrary test results ===
221
222 Very simply these three checks, xref:OP_PASS[`PASS`],
223 xref:OP_FAIL[`FAIL`] and xref:OP_SKIP[`SKIP`] generate the specified
224 result. They're intended to be used when what we're trying to test
225 doesn't quite fit into any of the two preceding ways of working.
226
227 == Suites ==
228
229 Suites serve to group tests into managable (and runnable) chunks, they
230 make it easy to have many tests defined, but only run those the
231 pertain to what we're currently working on. Suites, like tests, have a
232 name which can be used to retrieve the suite, and running a suite
233 simply causes all of the suite's tests to be run, if the suite
234 contains other suites, than those are run as well (and so on and so
235 on).
236
237 There is one suite that's a little special (in so far as it always
238 exists), the `T` suite. If you ignore suites completely, which is a
239 good idea at first or for small(ish) code bases, you're actually
240 putting all your tests into the `T` suite.
241
242 === Creating Suites ===
243
244 Suites are created in one of two ways: Either explicitly via the
245 xref:OP_DEF-SUITE[`def-suite`] macro, or implicity via the
246 xref:OP_DEF-SUITE-STAR-[`def-suite*`] and/or
247 xref:OP_IN-SUITE-STAR-[`in-suite*`] macros:
248
249 Suites, very much like tests, have a name (which is globally unique)
250 which can be used to retrieve the suite (so that you can run it), and,
251 most of the time, suites are part of a suite (the exception being the
252 special suite `T`, which is never a part of any suite).
253
254 [[THE_CURRENT_SUITE]]
255 === The Current Suite ===
256
257 FiveAM also has the concept of a current suite and everytime a test is
258 created it adds itself to the current suite's set of tests. The
259 `IN-SUITE` and `IN-SUITE*` macros, in a similar fashion to
260 `IN-PACKAGE`, change the current suite.
261
262 Unless changed via `IN-SUITE` and `IN-SUITE*` the current suite is the
263 `T` suite.
264
265 Having a default current suite allows developers to ignore suites
266 completly and still have FiveAM's suite mechanism in place if they
267 want to add suites in later.
268
269 [[RUNNING_SUITES]]
270 === Running Suites ===
271
272 When a suite is run we do nothing more than run all the tests (and any
273 other suites) in the named suite. And, on one level, that's it, suites
274 allow you run a whole set of tests at once just by passing in the name
275 of the suite.
276
277 [[RUNNING_TESTS]]
278 == Running Tests ==
279
280 The general interface is `run`, this takes a set of tests (or symbol
281 that name tests or suites) and returns a list of test results (one
282 element for each test run). The output of `run` is, generally, passed
283 to the `explain` function which, given an explainer object, produces
284 some human readable text describing the test failures. 99% of the time
285 a human will be using 5am (as opposed to a continuous integration bot)
286 they'll want to run the tests and immediately see the results with
287 detailed failure info, this can be done in one step via: `run!` (see
288 the first example).
289
290 If you want to run a specific test:
291
292 --------------------------------
293 (run! TEST-NAME)
294 --------------------------------
295
296 Where `TEST-NAME` is either a test object (as returned by `get-test`)
297 or a symbol naming a single test or a test suite.
298
299 === Re-running Tests ===
300
301 The functions `!`, `!!` and `!!!` rerun recently run tests (we store
302 the names passed to run! and simply call run! with those names again).
303
304 === Running Tests at Test Definition Time ===
305
306 Often enough, especially when fixing regression bugs, we'll always
307 want to run a test right after having changed it. To facilitate this
308 set the variable `*run-test-when-defined*` to T and after compiling a
309 def-test form we'll call `run!` on the name of the test. For obvious
310 reasons you have to set this variable manually after having loaded
311 your test suite.
312
313 [NOTE]
314 Setting `*run-test-when-defined*` will cause `run!` to get called far
315 more often than normal. `!` and `!!` and `!!!` don't know that they're
316 getting called semi-automatically and will therefore tend to all
317 reduce to the same test (which still isn't totally useless behaviour).
318
319 === Debugging failures and errors ===
320
321 `*debug-on-error*`::
322
323 Normally fiveam will simply capture unexpected errors, record them as
324 failures, and move on to the next test (any following checks in the
325 test body will not be run). However sometimes, well, all the time
326 unless you're running an automated regression test, it's better to not
327 capture the error but open up a debugger, set `*debug-on-error*` to
328 `T` to get this effect.
329
330 `*debug-on-failure*`::
331
332 Normally FiveAM will simply record a check failure and move on to the
333 next check, however it can be helpful to stop the check and use the
334 debugger to see what the state of execution is at the time of the
335 test's failure. Setting `*debug-on-failure*` to T will cause FiveAM to
336 enter the debugger whenever a test check fails. Exactly what
337 information is available is, obviously, implementation dependent.
338
339 [[VIEWING_TEST_RESULTS]]
340 == Viewing test results ==
341
342 FiveAM provides two "explainers", these are classes which, given a set
343 of results, produce some human readable/understandable
344 output. Explainers are just normal CLOS classes (and can be easily
345 subclassed) with one important method: `explain`.
346
347 The `run!` and `explain!` functions use the detailed-text-explainer,
348 if you want another explainer you'll have to call `run` and `explain`
349 yourself:
350
351 --------------------------------
352 (explain (make-instance MY-EXPLAINER)
353          (run THE-TEST)
354          THE-STREAM)
355 --------------------------------
356
357 == Random Testing (QuickCheck) ==
358
359 TODO.
360
361 Every FiveAM test can be a random test, just use the for-all macro.
362
363 == Fixtures ==
364
365 TODO.
366
367 they're macros with names. you can have tests (and suites)
368 automatically wrap themeselves in these macros. not much else to say.
369
370 [[API_REFERENCE]]
371 == API Reference ==
372
373 [[OP_DEF-TEST]]
374 === DEF-TEST ===
375
376 ================================
377 --------------------------------
378 (def-test NAME
379     (&key DEPENDS-ON SUITE FIXTURE COMPILE-AT PROFILE) 
380   &body BODY)
381 --------------------------------
382
383 include::docstrings/OP_DEF-TEST.txt[]
384 ================================
385
386 [[OP_DEF-SUITE]]
387 === DEF-SUITE ===
388
389 ================================
390 `(def-suite NAME &key DESCRIPTION IN FIXTURE)`
391
392 include::docstrings/OP_DEF-SUITE.txt[]
393 ================================
394
395 [[OP_IN-SUITE]]
396 [[OP_IN-SUITE-STAR-]]
397 === IN-SUITE / IN-SUITE* ===
398
399 ================================
400 `(in-suite NAME)`
401
402 include::docstrings/OP_IN-SUITE.txt[]
403 ================================
404
405 ================================
406 `(in-suite* NAME &key IN)`
407
408 include::docstrings/OP_IN-SUITE-STAR-.txt[]
409 ================================
410
411 [[OP_IS]]
412 === IS ===
413
414 ================================
415 ----
416 (is (PREDICATE EXPECTED ACTUAL) &rest REASON-ARGS)
417
418 (is (PREDICATE ACTUAL) &rest REASON-ARGS)
419 ----
420
421 include::docstrings/OP_IS.txt[]
422 ================================
423
424 [[OP_IS-TRUE]]
425 [[OP_IS-FALSE]]
426 === IS-TRUE / IS-FALSE / IS-EVERY ===
427
428 ================================
429 `(is-true CONDITION &rest reason)`
430
431 include::docstrings/OP_IS-TRUE.txt[]
432 ================================
433
434 ================================
435 `(is-false CONDITION &rest reason)`
436
437 include::docstrings/OP_IS-FALSE.txt[]
438 ================================
439
440 ////////////////////////////////
441 //// the actual doc string of talks about functionality i don't want
442 //// to publises (since it's just weird). se we use our own here
443 ////////////////////////////////
444 ================================
445 `(is-every predicate &rest (EXPECTED ACTUAL &rest REASON))`
446
447 Designed for those cases where you have a large set of expected/actual
448 pairs that must be compared using the same predicate function.
449
450 Expands into:
451
452 ----
453 (progn
454   (is (,PREDICATE ,EXPECTED ,ACTUAL) ,@REASON)
455   ...
456 ----
457
458 for each argument.
459 ================================
460
461 [[OP_SIGNALS]]
462 [[OP_FINISHES]]
463 === SIGNALS / FINISHES ===
464
465 ================================
466 `(signals CONDITION &body body)`
467
468 include::docstrings/OP_SIGNALS.txt[]
469 ================================
470
471 ================================
472 `(finishes &body body)`
473
474 include::docstrings/OP_FINISHES.txt[]
475 ================================
476
477 [[OP_PASS]]
478 [[OP_FAIL]]
479 [[OP_SKIP]]
480 === PASS / FAIL / SKIP ===
481
482 ================================
483 `(skip &rest REASON-ARGS)`
484
485 include::docstrings/OP_SKIP.txt[]
486 ================================
487
488 ================================
489 `(pass &rest REASON-ARGS)`
490
491 include::docstrings/OP_PASS.txt[]
492 ================================
493
494 ================================
495 `(fail &rest REASON-ARGS)`
496
497 include::docstrings/OP_FAIL.txt[]
498 ================================
499
500 [[OP_-EPOINT-]]
501 [[OP_-EPOINT--EPOINT-]]
502 [[OP_-EPOINT--EPOINT--EPOINT-]]
503
504 [[OP_RUN-EPOINT-]]
505 [[OP_EXPLAIN-EPOINT-]]
506 [[OP_DEBUG-EPOINT-]]
507 === RUN! / EXPLAIN! / DEBUG! ===
508
509 ================================
510 `(run! &optional TEST-NAME)`
511
512 include::docstrings/OP_RUN-EPOINT-.txt[]
513 ================================
514
515 ================================
516 `(explain! RESULT-LIST)`
517
518 include::docstrings/OP_EXPLAIN-EPOINT-.txt[]
519 ================================
520
521 ================================
522 `(debug! TEST-NAME)`
523
524 include::docstrings/OP_DEBUG-EPOINT-.txt[]
525 ================================
526
527 [[OP_RUN]]
528 === RUN ===
529
530 ================================
531 `(run TEST-SPEC)`
532
533 include::docstrings/OP_RUN.txt[]
534 ================================
535
536 === ! / !! / !!! ===
537
538 ================================
539 `(!)`
540
541 include::docstrings/OP_-EPOINT-.txt[]
542 ================================
543
544 ================================
545 `(!!)`
546
547 include::docstrings/OP_-EPOINT--EPOINT-.txt[]
548 ================================
549
550 ================================
551 `(!!!)`
552
553 include::docstrings/OP_-EPOINT--EPOINT--EPOINT-.txt[]
554 ================================
555
556 [[OP_FOR-ALL]]
557 === FOR-ALL ===
558
559 ================================
560 --------------------------------
561 (for-all (&rest (NAME VALUE &optional GUARD))
562   &body body)
563 --------------------------------
564
565 include::docstrings/OP_FOR-ALL.txt[]
566 ================================
567
568 [[VAR_-STAR-NUM-TRIALS-STAR-]]
569 [[VAR_-STAR-MAX-TRIALS-STAR-]]
570 === \*NUM-TRIALS* / \*MAX-TRIALS* ===
571
572 ================================
573 `*num-trials*`
574
575 include::docstrings/VAR_-STAR-NUM-TRIALS-STAR-.txt[]
576 ================================
577
578 ================================
579 `*max-trials*`
580
581 include::docstrings/VAR_-STAR-MAX-TRIALS-STAR-.txt[]
582 ================================
583
584 [[OP_GEN-INTEGER]]
585 [[OP_GEN-FLOAT]]
586 === GEN-INTEGER / GEN-FLOAT ===
587
588 ================================
589 `(gen-integer &key MIN MAX)`
590
591 include::docstrings/OP_GEN-INTEGER.txt[]
592 ================================
593
594 ================================
595 `(gen-float &key BOUND TYPE MIN MAX)`
596
597 include::docstrings/OP_GEN-FLOAT.txt[]
598 ================================
599
600 [[OP_GEN-CHARACTER]]
601 [[OP_GEN-STRING]]
602 === GEN-CHARACTER / GEN-STRING ===
603
604 ================================
605 `(gen-character &key CODE-LIMIT CODE ALPHANUMERICP)`
606
607 include::docstrings/OP_GEN-CHARACTER.txt[]
608 ================================
609
610 ================================
611 `(gen-string &key LENGTH ELEMENTS)`
612
613 include::docstrings/OP_GEN-STRING.txt[]
614 ================================
615
616 [[OP_GEN-BUFFER]]
617 === GEN-BUFFER ===
618
619 ================================
620 `(gen-buffer &key LENGTH ELEMENTS ELEMENT-TYPE)`
621
622 include::docstrings/OP_GEN-STRING.txt[]
623 ================================
624
625 [[OP_GEN-LIST]]
626 [[OP_GEN-TREE]]
627 === GEN-LIST / GEN-TREE ===
628
629 ================================
630 `(gen-list &key LENGTH ELEMENTS)`
631
632 include::docstrings/OP_GEN-LIST.txt[]
633 ================================
634
635 ================================
636 `(gen-tree &key SIZE ELEMENTS)`
637
638 include::docstrings/OP_GEN-TREE.txt[]
639 ================================
640
641 [[OP_GEN-ONE-ELEMENT]]
642 === GEN-ONE-ELEMENT ===
643
644 ================================
645 `(gen-one-element &rest ELEMENTS)`
646
647 include::docstrings/OP_GEN-ONE-ELEMENT.txt[]
648 ================================
649
650
651
652 ////////////////////////////////
653
654 ////////////////////////////////