# Testing Deft ships a built-in test framework: `defsuite` groups tests, `deftest` defines individual cases, and the `assert/` namespace checks outcomes. The `deft test` command runs `.dft` files matching `test_*.dft` or explicitly named files. ## Hello, Test
 defsuite "arithmetic" {
    deftest "addition" {
        [assert/eq (1 + 2) 3]
    }

    deftest "multiplication" {
        [assert/eq (2 * 3) 6]
    }
} 
Run with: ``` deft test test_math.dft ``` ## Assertions Each assertion is its own stdlib function under the `assert/` namespace — no kind keyword, just the slash-separated name:
 [assert/eq $a $b]                 # equality
[assert/ne $a $b]                 # inequality
[assert/truthy $x]                # truthy
[assert/falsy $x]                 # falsy
[assert/gt $a $b]                 # greater than
[assert/gte $a $b]                # greater than or equal
[assert/lt $a $b]                 # less than
[assert/lte $a $b]                # less than or equal
[assert/nil? $x]                  # nil check
[assert/not-nil? $x]              # not-nil check
[assert/empty? $xs]               # empty collection
[assert/not-empty? $xs]           # non-empty collection
[assert/contains? $xs $v]         # collection contains value
[assert/type $x "number"]         # type check
[assert/length $xs $n]            # length check 
For predicates that already end in `?`, use the matching `assert/` form directly:
 [assert/nil? $result]
[assert/truthy [empty? $xs]] 
### Custom assertion messages The optional last argument is a failure message:
 [assert/eq $status 200 "expected HTTP 200"] 
## Test Discovery `deft test` with no arguments looks for `test/test_*.dft` relative to the current directory. Pass paths explicitly to run a subset: ``` deft test # all tests under ./test/ deft test test_sqlite.dft # one file deft test test/test_sqlite.dft test/test_atoms.dft # several ``` ## Writing Good Tests ### Use type hints on the system under test
 def add {|a^number b^number| ($a + $b) }

defsuite "add" {
    deftest "positive" { [assert/eq [add 1 2] 3] }
    deftest "negative" { [assert/eq [add -1 -2] -3] }
    deftest "zero"     { [assert/eq [add 0 0] 0] }
} 
### Test Results, not just success
 defsuite "json/parse" {
    deftest "valid" {
        set r [json/parse "{\"a\":1}"]
        [assert/eq $r~a 1]
    }

    deftest "invalid" {
        set r [json/parse "not json"]
        [assert/truthy [err? $r]]
    }
} 
### Test that code throws Wrap the call in a `try` and assert the catch branch ran:
 defsuite "divide" {
    deftest "by zero throws" {
        set caught false
        try {
            [divide 1 0]
        } catch _e {
            set caught true
        }
        [assert/truthy $caught]
    }
} 
### Higher-order function tests
 defsuite "map" {
    deftest "applies f" {
        set result @{ 1 2 3 } |> map { $it * 2 } |> collect
        [assert/eq $result @{ 2 4 6 }]
    }

    deftest "lazy on infinite" {
        set result [range 0 1000] |> filter even? |> take 3 |> collect
        [assert/eq $result @{ 0 2 4 }]
    }
} 
### Pipeline tests
 defsuite "pipeline" {
    deftest "chain" {
        set result @{ 1 2 3 4 }
            |> map { $it * $it }
            |> filter { $it > 4 }
            |> collect
        [assert/eq $result @{ 9 16 }]
    }
} 
### User-defined type tests
 deftype Point %{ :x %{:type :number} :y %{:type :number} }

defsuite "Point" {
    deftest "construction" {
        set p %Point{ :x 3 :y 4 }
        [assert/eq $p~x 3]
        [assert/eq $p~y 4]
    }
} 
### Function-value tests Functions are first-class; assert their return values:
 defsuite "factorial" {
    def factorial {|n|
        if ($n <= 1) { 1 } { ($n * [factorial ($n - 1)]) }
    }

    deftest "base case" { [assert/eq [factorial 0] 1] }
    deftest "recursive" { [assert/eq [factorial 5] 120] }
} 
## Benchmarks `defbench` declares a benchmark case. Run with `deft test --bench`:
 defsuite "fib perf" {
    defbench "fib 20" {
        [fib 20]
    }
} 
The runner reports wall-clock time per iteration. Use it to spot regressions in hot paths. ## Best Practices 1. **One concept per suite.** Group tests by the function or type they exercise, not by output shape. 2. **Test names should read like specs.** `"add positive numbers"`, not `"test1"`. 3. **Don't share mutable state across tests.** Each `deftest` should construct its own fixtures. 4. **Prefer pure assertions over `echo` inspection.** Asserts are machine-checkable; printed output isn't. 5. **Test failure modes, not just happy paths.** Wrap calls in `try` to verify error behaviour. ## CI Integration A typical GitHub Actions step: ```yaml - name: Run tests run: | zig build deft -Doptimize=ReleaseFast ./zig-out/bin/deft test ``` For FFI tests: ```yaml - name: Build with FFI run: zig build deft -Dffi=true -Doptimize=ReleaseFast - name: Run FFI tests run: ./zig-out/bin/deft test test/test_ffi.dft ``` ## Quick Reference | Form | Purpose | |---|---| | `defsuite "name" { ... }` | Group tests | | `deftest "name" { ... }` | Individual case | | `defbench "name" { ... }` | Benchmark case | | `[assert/eq actual expected]` | Assertion | | `deft test [files...]` | Run tests | | `deft test --bench` | Run benchmarks |