All checks were successful
/ test (push) Successful in 9s
Safsaf is a Guile web framework, written using Claude Code running Claude Opus 4.6, based off of the Guix Data Service, Nar Herder and Guix Build Coordinator codebases.
73 lines
2.1 KiB
Markdown
73 lines
2.1 KiB
Markdown
# Testing
|
|
|
|
## Framework
|
|
|
|
Tests use a minimal SRFI-269 implementation in `(tests support)`. Three
|
|
primitives — `is`, `test`, `suite` — build first-class test entities and
|
|
deliver them to a pluggable runner. Definition is separated from execution.
|
|
|
|
## Running tests
|
|
|
|
All tests (via Automake):
|
|
|
|
make check
|
|
|
|
Single file:
|
|
|
|
./pre-inst-env guile tests/test-router.scm
|
|
|
|
## Writing tests
|
|
|
|
```scheme
|
|
(use-modules (tests support)
|
|
(safsaf router)) ; module under test
|
|
|
|
(define-suite router-tests
|
|
(suite "route construction"
|
|
(test "creates route with method and pattern"
|
|
(let ((r (route 'GET '("users") identity)))
|
|
(is (route? r))
|
|
(is (eq? 'GET (route-method r))))))
|
|
|
|
(suite "matching"
|
|
(test "exact path match"
|
|
...)))
|
|
|
|
(run-tests router-tests)
|
|
```
|
|
|
|
Key points:
|
|
|
|
- `(is expr)` — assert expr is truthy. Returns the value on success.
|
|
- `(is (pred arg ...))` — predicate form; on failure shows evaluated args.
|
|
- `(test "desc" body ...)` — a single test case with one or more assertions.
|
|
- `(suite "desc" body ...)` — group tests and nested suites.
|
|
- `(define-suite name body ...)` — bind a suite-thunk to a variable.
|
|
- `(run-tests thunk)` — run with the simple runner, print summary, exit.
|
|
- Tests should be self-contained: don't depend on ordering or side effects
|
|
from other tests.
|
|
- Use `define` inside `test` bodies for local setup.
|
|
|
|
## Synthetic requests
|
|
|
|
Many tests need Guile `<request>` objects without a real HTTP server.
|
|
Build them with `build-request` from `(web request)`:
|
|
|
|
```scheme
|
|
(use-modules (web request) (web uri))
|
|
|
|
(define* (make-request method path #:optional (headers '()))
|
|
(build-request (build-uri 'http #:host "localhost" #:path path)
|
|
#:method method
|
|
#:headers headers))
|
|
```
|
|
|
|
Handler signature is `(request body-port) → (values response body)`. When
|
|
calling handlers or wrapped handlers in tests, pass `#f` as the body-port:
|
|
|
|
```scheme
|
|
(let ((resp body (wrapped (make-request 'GET "/" '()) #f)))
|
|
(is (= 200 (response-code resp))))
|
|
```
|
|
|
|
For handlers that read `current-route-params`, `parameterize` it directly.
|