2025-08-29

(sph test)

test guile scheme modules and procedures.

features

test definition

  • tests grouped into modules, modules composable
  • simple syntax for input/output
  • nestable assertions with concatenated titles
  • hooks for before/after/inbetween, custom reporters
  • using modules is optional

execution

  • all test code compiled before running (no compile messages during run)
  • modules can extend runner settings
  • no restriction on execution strategy (e.g. repeat, parallel)
  • tests across multiple files can run as one with grouped output
  • "only" and "exclude" filters available

interface

  • scheme interface: run tests from scheme (e.g. ci)
  • stdout reporting optional
  • "compact" reporting format for efficiency
  • reporters extendable, selected via settings

implementation

  • tests are procedures
  • modules are r6rs libraries
  • functional style, no hidden state, no goops, no opaque types

asserts

all accept optional title string. nested titles concatenate.

(assert-true (= 3 (+ 2 1)))
(assert-true "addition" (= 3 (+ 2 1)))
(assert-equal "addition" (+ 1 2) 3)
(assert-and "group"
  (assert-true "a" (= 3 (+ 2 1)))
  (assert-equal "b" (+ 5 4) 6)
  (assert-true (+ 2 1)))

examples

test module file

(define-test-module (test module sph string)
  (import (sph string))
  (test-execute-procedures-lambda
    (string-indices
      ("/a////b//c/d" "/") (0 2 3 4 5 7 8 10)
      ("abcd" "bc") (1))
    (string-multiply
      ("a" 3) "aaa")
    (string-replace-string
      ("abcd" "bc" "") "ad")))

compact report

string-indices 1 2
string-multiply 1
string-replace-string 1

failure report

string-quote 1
  failure string-quote 2
  inp "t'est"
  exp "\"t'est\"x"
  out "\"t'est\""

multiple modules

test module sph vector
  vector-append 1
test module sph record
  define-record 1

usage

define module

(define-test-module (test module mymodule)
  (import (mymodule))
  (lambda (settings)
    (assert-true "addition" (= 3 (+ 2 1)))))

define tests

(define-test (name args ...) test-result)
(define-test (abc) #t)
(define-test (abc args expected) #t)
(define-test (abc name index args expected) #t)

run modules

(import (sph) (sph test))
(define settings (test-settings-default-custom path-search "modules" reporter-name (q compact)))
(test-execute-modules-by-prefix #:settings settings (q (test module sph)))

settings (default excerpt)

(define-as test-settings-default alist-q
  reporters test-reporters-default
  reporter-name (q default)
  search-type (q prefix)
  hook
  (alist-q procedure-before ignore procedure-after ignore)
  random-order? #f
  parallel? #f
  exception-strings? #t
  exclude #f
  only #f
  until #f)

implementation notes

  • modules are r6rs libraries exporting execute
  • execute :: settings -> test-result
  • modules provide scope separation and names
  • test-result can be list/record/boolean
  • define-test avoids manual "test-" prefix

excluded

  • cps-style tests with "done"
  • terminal coloring
  • "fun" reporters
  • implicit multi-return values

enhancements

  • count tests
  • reporters for csv/scm
  • define-test-module without wrapping
  • test-module composition

references

  • mocha, trc-testing, rails testing
  • scheme libs: bunny-test, guile-lib unit-test, schemeunit, srfi-64, test-manager, testeez