74 lines
2.1 KiB
Markdown
74 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.
|