Beyond pass/fail.
Code coverage, doc extraction, per-example timing, slow-test detection, memory profiling, statistical benchmarking with regression detection. All built in, all driven by the same runner, all activated with a single flag.
#code coverage
Line coverage for the code your specs exercise. No extra modules, no plugins.
Pass --coverage, point at your lib/, and Behave records
which lines ran during the test suite.
⮑ 'Account'
⮑ 'starts with the configured balance'
⮑ SUCCESS
⮑ 'increases the balance on deposit'
⮑ SUCCESS
2 examples, 0 failed, 2 passed
Coverage: lib/Account.rakumod 100% 42 / 42
lib/ShoppingCart.rakumod 96% 48 / 50 miss: 33, 41
lib/Invoice.rakumod 78% 61 / 78 miss: 22-29, 51-58, 66
lib/Receipt.rakumod 12% 3 / 25 miss: 4-9, 12-25
Total 82% 154 / 195
--coverage with --format json
and the report ships with structured coverage data your pipeline can gate on.
#doc extraction
Your specs already describe what the code does in English. Behave's doc extractor turns them into Markdown. Descriptions become headings, examples become prose, nested groups become nested sections. The cheapest documentation you'll ever ship is the documentation you already wrote.
# Calculator
## addition
- adds positive numbers
- overflows on MAX_INT
- handles negative-zero (pending: not yet implemented)
## subtraction
- subtracts a positive from a positive
- subtracts a negative from a positive
# Account
- starts with the configured balance
## after a deposit
- increases the balance
- records the transaction
- emits a deposit event
The richer DocExtractor module lets you script your own pipeline: pull
the spec tree, walk it, render to any target format your team uses.
#timing & slow-test detection
Every example is timed. Pass --profile for a "top N slowest" report,
or --slow-threshold N to flag any example over N seconds
inline as it runs. No instrumentation, no separate tooling.
⮑ 'integration'
⮑ 'talks to the database'
⮑ SUCCESS (SLOW: 0.43s)
⮑ 'renders the report'
⮑ SUCCESS
12 examples, 0 failed, 12 passed
Top 5 slowest examples:
0.43s integration talks to the database specs/db-spec.raku:8
0.27s reports renders the report specs/report-spec.raku:14
0.11s auth signs and verifies a JWT specs/auth-spec.raku:22
0.04s cache evicts the oldest entry specs/cache-spec.raku:31
0.03s parser handles deeply nested expressions specs/parser-spec.raku:67
#memory profiling
--memory-profile records per-example RSS delta and prints a
"top N memory-heaviest" report. --memory-threshold KB flags any
example whose memory growth exceeds the threshold inline. Useful for catching
leaks in long-running fixtures.
⮑ 'image processing'
⮑ 'resizes a 4k jpeg'
⮑ SUCCESS (MEMORY: +5.8 MB)
⮑ 'thumbnails a batch'
⮑ SUCCESS
Top 3 memory-heaviest examples:
+5.8 MB image processing resizes a 4k jpeg specs/img-spec.raku:8
+0.9 MB reports builds the PDF specs/report-spec.raku:32
+0.3 MB parser parses 10k lines specs/parser-spec.raku:54
#benchmarks & regression detection
Behave includes a benchmark harness with statistical summaries (mean, median, stddev, iterations) and an optional baseline file so you can detect regressions across runs. Mark a block as a benchmark. Behave records, summarizes, and (if enabled) compares.
use BDD::Behave;
use BDD::Behave::Benchmark;
describe 'serialization', {
benchmark 'json encode a 10k-row payload', {
JSON::Fast::to-json(@payload);
}
benchmark 'msgpack encode a 10k-row payload', {
MsgPack::encode(@payload);
}
}
Benchmarks:
json encode a 10k-row payload
mean: 4.21ms median: 4.18ms stddev: 0.11ms iter: 200
vs baseline: +2.4% faster
msgpack encode a 10k-row payload
mean: 1.83ms median: 1.80ms stddev: 0.06ms iter: 200
vs baseline: -11.7% regression ⚠
Regressions detected (threshold 5%): 1
BDD::Behave::Bisect module narrows
down which example introduces a failure when running a test ordering. Think
git bisect, but for spec order dependencies.
#diff output
When an eq or be matcher fails on a structural value,
Behave renders a colorized inline diff alongside the standard
Expected: / to be: block. No more eyeballing two
twenty-line hashes side by side.
⮑ 'User#to-hash'
⮑ 'serializes the user'
⮑ FAILURE
Failures:
[ ✗ ] specs/user-spec.raku:18
Expected: { name => "Ada", role => "admin", age => 31 }
to be: { name => "Ada", role => "user", age => 30 }
Diff:
{
name => "Ada",
- role => "admin",
+ role => "user",
- age => 31,
+ age => 30,
}
1 example, 1 failed, 0 passed