Bats Concepts
Internal
Overview
Shell scripts can be tested easier if the functionality is broken into many small, reusable and independently testable functions. A library that packages such functions can be tested by sourcing the library into the BATS test and then running the functions no different than how their usual calling layer would invoke them.
bats-core vs bats
Apparently bats-core supersedes bats, and it should be used instead. One difference is that bats error reports are included as comments, not part of tap output, and are not therefore propagated to the Xunit version of tap-xunit. In other words, bats-core includes builtin xunit output.
Test
An individual test is placed into a @test-annotated code block.
@test "something" {
run my-command status
[[ ${status} -eq 0 ]] || echo "${output}"
[[ ${output} =~ We[[:space:]]are[[:space:]]good ]] || echo "${output}"
}
The quoted-enclosed label that follows @test may include spaces.
The functionality to be tested, most likely a function, must be executed with "run", as shown above. If executed that way, ${status} and ${output} are updated accordingly.
Tests are executed in the order they're specified in the file.
In all tests, $0 is /usr/local/Cellar/bats/0.4.0/libexec/bats-exec-test
(or wherever BATS was installed on the system).
Displaying from Test
@test "something" {
run ...
echo ${status}
}
Test Environment
BATS uses exec
to run each @test
block as a separate subprocess. This makes it possible to export environment variables and even functions in one @test
without affecting the other @test
s or polluting the current shell session.
Run a Command and Check the Status and Output
some_command=....
[...]
run ${some_command}
[[ ${status} -eq 0 ]]
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]
${status}
[[ ${status} == 0 ]] || { echo ${output}; exit 1; }
[[ ${status} -eq 0 ]] || { echo ${output}; exit 1; }
${output}
$(output)
coalesce lines:
some_command=....
[...]
run ${some_command}
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]
[[ -z ${output} ]] || { echo ${output}; exit 1; }
${lines}
For multi-line output, individual lines can be accessed with:
${lines[0]} ${lines[1]} ...
As in ${output}'s case, sdtout and stderr are coalesced.
To test the number of lines:
[[ ${#lines[@]} == 3 ]]
Setup/Teardown
If the BATS script includes setup()
and teardown()
functions, they are automatically executed by BATS before and after each test block runs.
function setup() {
...
}
function teardown() {
...
}
Libraries being Tested and Helpers
Like any shell script or library, BATS test scripts can include helper libraries to share common code across tests. Libraries can be placed in the same test directory as the BATS scripts or in the test/libs
directory, and loaded with the load
function. The load
function takes a path to a bash file relative to the script being tested and sources that file. Files must end with the .bash
prefix, but the path to the file passed to the load
function must not include the prefix.
Also see:
Environment Variables
BATS_TEST_DIRNAME
The directory in which the Bats test file is located.
BATS_TMPDIR
The location to a directory that may be used to store temporary files.
BATS_TEST_NAMES
Array.
BATS_TEST_NUMBER
The (1-based) index of the current test case in the test file.