bats-testing-patternslisted
Install: claude install-skill uwuclxdy/agenticat
# Bats Testing Patterns
Bats (`bats-core`) runs `.bats` files as TAP-compliant Bash tests. Each `@test` block runs in its own subshell/process; state never leaks between tests. `export` a variable when a command run via `run` within the same test needs to see it.
## Test File Anatomy
```bash
#!/usr/bin/env bats
setup() { # before EACH test
export SCRIPT="${BATS_TEST_DIRNAME}/../bin/script.sh"
}
setup_file() { # once, before the file's first test
export FIXTURE_DB="$BATS_FILE_TMPDIR/seed.db"
}
@test "script exits 0 with a valid config" {
run "$SCRIPT" --config "$BATS_TEST_TMPDIR/valid.conf"
[ "$status" -eq 0 ]
}
```
`teardown` mirrors `setup` and runs after every test; skip it when `$BATS_TEST_TMPDIR` already covers cleanup. Use `$BATS_TEST_TMPDIR` (unique per test) instead of hand-rolled `mktemp -d`/`rm -rf`: bats creates and clears it automatically, so a test can't leak state into the next one even if `teardown` never runs. `$BATS_FILE_TMPDIR` is the per-file equivalent for `setup_file`/`teardown_file`; `$BATS_SUITE_TMPDIR` spans the whole suite.
## The `run` Helper
`run` captures a command's exit status into `$status` and its combined stdout+stderr into `$output` (also split into the `$lines` array). It always returns 0, so the test keeps going after a failing command.
```bash
@test "rejects an unknown flag" {
run -1 my_script --bogus # -N: assert exit status N; bare `!` asserts any nonzero
[[ "$o