Command-line options
Everything after -- in dub test :pkg -- <options> goes to the runner.
Selection and output
| Option | Description |
|---|---|
-i, --include | Run only tests whose fullName name matches the regular expression |
-e, --exclude | Skip tests whose fullName name matches; combines with -i (a test must match -i and not match -e) |
-v, --verbose | Durations, [file:line] locations, full stack traces |
-t, --threads | Worker threads; 0 (default) auto-detects, 1 runs single-threaded |
--no-colors | Disable colored output (also honors $NO_COLOR and non-tty stdout) |
-l, --list | List discovered tests with @ctfe/@benchmark/@workload/@betterC/@wasm markers |
--self-test | Also run the test runner's own unittests |
-h, --help | Option summary |
Modes
| Option | Description |
|---|---|
| (none) | Run regular tests in parallel; evaluate selected @ctfe tests via CTFE. On an interactive stdout a polled progress line (⠹ 12/40 (1.2s)) redraws beneath the streaming result lines and is erased before the summary — suppressed by the same rules as the --bench spinner |
--bench | Measure @benchmark tests (serial), then @workload tests under the window model — one single-pass window per workload (counter deltas + a wall-clock decomposition), rendered as a final workloads table. Cases are registered from all bench bodies, then scheduled and measured grouped by their streaming key — the --group-by group, else the source test — with timing and metric columns aligned on the decimal point and consecutive tables sharing their column geometry. On an interactive stdout each group's table ticks live: it repaints in place, growing a row per measured case with a dim ⠹ name │ measuring… row for the case in flight, then graduates into scrollback when the group completes. With stdout redirected but stderr on the terminal, a one-line spinner (⠹ 12/40 name) animates on stderr instead; both displays obey the same suppression rules (piped, non-tty, --no-colors, $NO_COLOR, TERM=dumb), and a piped run prints each table once, byte-stable |
--perf | With --bench: add hardware perf counters per benchmark — on Linux via perf_event (IPC, instructions/iter, cache/branch miss rates), on macOS via the unprivileged proc_pid_rusage fixed counters (IPC + instructions/iter; process-wide, disclosed in the header). A group that opened but is not in its clean default state (user-only fallback, dropped LLC pair, scaled mode) is disclosed with one header line |
--perf-scaled | With --perf: keep the full counter group when the PMU would multiplex it. Default: the group shrinks (LLC pair first) at open to avoid multiplexing. In either mode, any cell whose pass was actually scaled renders as a labeled estimate (≈ prefix; named in --bench-json's estimatedMetrics), and a multiplexed pass with under 1 ms of PMU time renders —, never a number |
--perf-iters=N | With --bench: pin the counting-pass iteration count (default: the timing pass's count, capped) — makes per-pass counter totals and amortized one-time costs reproducible across runs. The effective count lands in every --bench-json row as countIterations |
--syscalls[=LIST] | With --bench: count syscalls/iteration (perf tracepoints); bare = total column, =futex,… adds one each. Needs readable tracefs + perf_event_paranoid ≤ 1 (usually root) |
--metrics=LIST | With --bench: choose metric columns (comma list; glob with *; all = every available; ?/help = list). Default: standard. Naming a perf metric (or all) opens the --perf pass automatically, and naming syscalls/syscalls:<name> opens the --syscalls pass; a selector that matches nothing warns on stderr. raw:r<hex> adds a raw hardware event by config (the perf tool's rNNNN notation), and pfm:<name> a symbolic µarch event resolved through libpfm4 when present (umask + :u/:k modifier grammar) — both count in their own group, so the default columns stay exact |
--list-metrics | List the available metric columns (name, class, source) and exit, followed by a per-backend capability block — one ✓/✗ line per capability each backend can or cannot deliver on this host, with the reason for every absence (e.g. ✗ eventTracing — tracefs event ids unreadable — usually root); the wall block reports the workload decomposition source. Works with or without --bench |
--sort-by=KEY | With --bench: sort rows by name or a metric column name (ascending; sc:<name> and syscalls:<name> are the same column). Default: median/iter. Applied within --group-by groups; error rows always sort last. An unknown column name warns on stderr and leaves the default order |
--bench-json=FILE | With --bench: also write the results as JSON (schema 2) — every row in measurement order (error rows included) plus a meta block (host, compiler, effective knobs), with metrics keyed by catalog names and estimated values named per row in estimatedMetrics; @workload results land in a windows sibling array (window totals + the wall decomposition, null = unattributable). Deterministic; for committed baseline snapshots. A write failure fails the run |
--bench-min-time=MS | With --bench: per-case measurement budget in milliseconds (default 5) — per-call benchCase rows: minimum total measured time; batched (benchIter/whole-body): target per sample. Inert for pinned @benchmark(iterations: N) |
--group-by=KEYS | With --bench: split the report into one table per group of the given case label keys (comma-separated or repeated; each titled benchmark: <group> over an implementation column listing the row name). E.g. =dataset,operation. =all groups by every label key; =list prints the available keys and exits |
--better-c | Extract @betterC tests, compile with -betterC, run without druntime |
--wasm | Extract @wasm tests, cross-compile to wasm32, run in a wasm runtime |
--ctfe-trace FILE | Evaluate @ctfe tests under LDC -ftime-trace and report per-test cost |
The run modes are mutually exclusive: combining --bench, --ctfe-trace, and --better-c/--wasm is an error (--better-c with --wasm is fine — one extraction family), while --list/--list-metrics are queries that win over any mode. Under --bench, an assert-enabled (debug) build prints a warning on stderr — dub's stock unittest build type is one; real numbers need an optimized unittest buildType.
@ctfe tests are evaluated by a probe program compiled with -o- -unittest (semantic analysis only) after -i/-e filtering, so only the selected tests execute, and --help/--list never evaluate any — even ones that would fail. See Write compile-time tests.
@ctfe / --better-c / --wasm toolchain options
| Option | Description |
|---|---|
--compiler DC | D compiler to use (default: $DC, then ldc2, dmd from PATH) |
-I, --import-path DIR | Extra import path (repeatable) |
--include-import PATTERN | Compile matching imported modules in (-i=PATTERN; repeatable) |
--no-auto-include | Don't compile the extracted tests' own modules in |
--require-toolchain | Fail instead of skipping when an extracted mode's tools are gone |
--keep | Keep the generated program files and print their location |
Skipped tests
A test may skip itself at runtime with skipTest("reason") (see Skip tests at runtime): it renders as a yellow ⊘ line with the reason, adds a , N skipped segment to the summary, and never fails the run. Under --bench, a case-level skip is a yellow row in its table.
Exit status
0 when everything passed or was skipped (skipTest, or a toolchain-missing mode); non-zero otherwise.