Skip to content
shellhacks.dev
Testing

Check output in Bats

Capture a command's output and status in Bats with run, then assert on $output and $status. run keeps a failing command from ending the test early.

2 min read
Summarize in AI

A test needs to check what a command printed, and to check that it failed in the right way.

Shell
cat > out.bats <<'EOF'
@test "output is checked as a whole string" {
  run echo "hello world"
  [ "$status" -eq 0 ]
  [ "$output" = "hello world" ]
}

@test "output can be matched as a pattern" {
  run printf 'one\ntwo\nthree\n'
  [[ $output == *two* ]]
  [ "${lines[1]}" = "two" ]
  [ "${#lines[@]}" -eq 3 ]
}

@test "a failing command is captured, not fatal" {
  run ls /nonexistent
  [ "$status" -ne 0 ]
  [[ $output == *"No such file"* ]]
}

@test "mismatch shows the failing line" {
  run echo "hello"
  [ "$output" = "bye" ]
}
EOF
bats out.bats
Text
1..4
ok 1 output is checked as a whole string
ok 2 output can be matched as a pattern
ok 3 a failing command is captured, not fatal
not ok 4 mismatch shows the failing line
# (in test file out.bats, line 22)
#   `[ "$output" = "bye" ]' failed

run executes the command, stores its combined standard output and standard error in $output, its exit status in $status and the output split by lines in the $lines array, all described in the Bats guide to writing tests. Because run always returns 0 itself, a command that fails cannot end the test before you look at $status. The last test shows the report for a failed assertion: the file, the line and the command.

$output merges both streams, so the order of stdout and stderr lines can differ from the terminal. Use run --separate-stderr from Bats 1.5 to keep them apart. Do not call run on a shell function that changes variables, as it executes in a subshell and the changes are lost.

Share

More snippets

Testing

Choose the shell for ShellCheck

Tell ShellCheck which shell a script targets with -s bash or -s sh. Without a shebang it cannot tell, and as sh it flags every Bash-only feature as SC3xxx.

2 min read
Testing

Skip a Bats test

Skip a Bats test with skip or skip "reason", which can be called in the middle of a test. A skipped test counts as passed, and the reason shows in the output.

2 min read
Testing

Load helpers in Bats

Share code between Bats tests with load helpers, which reads helpers.bash from the test file's directory. A plain source breaks when bats runs from elsewhere.

2 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.