[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Integrating unit tests into source code

From: Michele Simionato
Subject: Re: [Chicken-users] Integrating unit tests into source code
Date: Thu, 14 Dec 2006 12:00:06 +0100

On 12/14/06, felix winkelmann <address@hidden> wrote:

While reading a bit about "doctest" (the Python utility), I thought
it would be relatively easy to support embedded documentation
in definitions, like:

(define (foo ...)
  '(test (...))

The basic idea is to extend the idea of Lisp/Scheme docstrings
(a string as the first form inside a procedure, when the body
has more than one expression) to doc-sexprs.
So one could embed test-cases directly in the code, in a backwards-
and R5RS-compatible way.

It's no big deal to extend the compiler to extract this info. What I'm
looking for is ideas about the exact mechanism, the syntax, etc.

Pointless or useful?

I am an heavy user of doctests, I have given a couple of talks on
the subject, and I have experimented a lot with them.

FWIW, this is what I do:

1. I use doctests in the canonical form (tests inside the function docstring)
  with extreme moderation, because I don't like gigantic docstrings;

2. I use doctests in the module-level docstring *a lot*;

3. I put doctests which are more "tests" than "doc" in a separate
  text file, so they don't bother the reader of the code.

The best solution, IMO, is to do literate programming: I have a hand made
utility that extracts the docstrings from a module (or sets of modules) and
i) generate a nice looking PDF documentation; ii) run all the tests contained
in the documentation.

In theory, doctests allows you to insert text in your code: but I have
perverted them enough that now I just insert the code in my text. This
is the literate programming way, and I like it very much. For a concrete
example, you can look at the documentation of my decorator module

I must add that I have completely removed all my unittests. I prefer very
much to put my tests in the documentation, so that I am sure that the
documentation is always updated. I often write support code to make my
doctest look nicer.

Using s-expr based doctests may be fine, but it goes in a completely
different direction than literate programming.

Having said that, a couple of years ago I did some experiment with
a doctest-inspired testing framework. Here is some code which was
sitting on my hard disk:

(use srfi-1 miscmacros)

(define *test-count* 0)
(define *fail-count* 0)

;; a saner try-except statement, introduces a binding for exn
(define-macro (try expr . error-management)
 `(handle-exceptions exn (begin ,@error-management) ,expr))

;; convert a condition into an error string
(define (format-exn exn)
 (define loc (or ((condition-property-accessor 'exn 'location) exn) ""))
 (define msg ((condition-property-accessor 'exn 'message) exn))
 (define arguments ((condition-property-accessor 'exn 'arguments) exn))
 (define args (if (null? arguments) "" (str-drop arguments 1 1)))
 (sprintf "Error: (~a~a) ~a" loc args msg))

;; a nice looking assert macro for doctesting
(define-macro (>> . body)
 (let ((got (gensym)) (exp (gensym)))
    (define ,exp ,(last body))
    (define ,got (try (begin ,@(butlast body)) (format-exn exn)))
    (inc! *test-count*)
    (unless (equal? ,got ,exp)
        (inc! *fail-count*)
        (printf "FAIL: test #~a, got ~a\nexpected ~a\n"
                *test-count* ,got ,exp)))))

(define (show-test-results)
 (printf "~a tests, ~a ok, ~a fail\n"
         *test-count* (- *test-count* *fail-count*) *fail-count*))

;; example
(>> (+ 1 1)

That's all,

                                Michele Simionato

reply via email to

[Prev in Thread] Current Thread [Next in Thread]