I'd like to show, how easy it is to do unit testing in the Scheme
programming language without additional tools or libraries. Here I've
written a few lines which are sufficient to be appropriate generic
test code:
- Code: Select all
(define-macro (break-on-error?) #t)
(define-macro (deftest name testproc)
`(define (,name)
(mk-err-report-cond ,name (call/cc ,testproc))))
(define (runtests maintestproc)
(call/cc
(lambda (break)
(define (check testproc)
(define err-report (testproc))
(when err-report
(write err-report)
(newline)
(if (break-on-error?)
(break))))
(maintestproc check))))
(define (mk-err-report-cond location details)
(and location details
`((tag . err-report)
(location . ,location)
(details . ,details))))
- Code: Select all
(define (my-double x)
"not implemented")
(define (my-square x)
(+ x x)) ;;wrong
- Code: Select all
(deftest test-my-double
(lambda (return)
(let ((res (my-double 3)))
(if (not (number? res))
(return 'not-a-number))
(if (not (= res 6))
(return 'oops!)))
#f))
(deftest test-my-square
(lambda (return)
(let ((res (my-square 5)) (w 25))
(if (not (number? res))
(return 'not-a-number))
(if (not (= res w))
(return `(wrong: ,res should-be: ,w))))
#f))
(runtests
(lambda (check)
(check test-my-double)
(check test-my-square)
))
mk-err-report-cond; here it's just an easy association list
(convenient for further processing by Scheme procedures).
Depending on whether the first failing test shall break further test
execution or not, the definition of why break-on-error? may be
modified.
The unhygienic macro system (define-macro) is used rather than the
hygienic ones because of simplicity.
I'm used to have fun when reading Scheme source code, so I hope you
enjoy it, too!
Regards
Thomas

