This is one of the few (IMO) legitimate uses of `eval`.
Your test suite should create a namespace, set it up by requiring your language's module, and then eval interactions expressed as quoted S-expressions or syntax objects. Here's a basic example for testing `match`:
#lang racket/base
(require syntax/strip-context rackunit)
(define test-ns (make-base-empty-namespace))
(parameterize ((current-namespace test-ns))
(namespace-require 'racket/base)
(namespace-require 'racket/match))
;; test-eval : (U Syntax S-expr) -> Any
(define (test-eval expr)
(parameterize ((current-namespace test-ns))
(eval `(#%top-interaction
. ,(cond [(syntax? expr)
(namespace-syntax-introduce
(strip-context expr))]
[else expr])))))
(check-equal? (test-eval
'(match (list 1 2 3)
[(cons x ys) x]
[_ #f]))
1)
(void (test-eval '(define null? zero?))) ;; !!!
(check-equal? (test-eval
#'(match 0
[(? null?) 'ok]
[_ 'no]))
'ok)
The call to `strip-syntax` is necessary in the second test to make `null?` refer to the redefinition in the testing namespace instead of the normal binding visible to the testing module.
Ryan