Unit Testing Functions with Bats-core
Structure test files, assertions, and setup/teardown to verify individual Bash functions.
What Is Bats-core and Why Use It?
Bats-core (Bash Automated Testing System) is the de-facto unit testing framework for Bash. It lets you write structured, repeatable tests for your shell functions and scripts — the same way you would use JUnit for Java or pytest for Python.
- Each test is a
@testblock with a human-readable description. - Tests pass when every command inside returns exit code
0. - Tests fail on the first non-zero exit code or a failed assertion.
- Output is TAP-compatible, so CI systems (GitHub Actions, Jenkins, GitLab CI) understand it natively.
Install via your package manager or clone the repository:
# Install via git (recommended — always latest)
git clone https://github.com/bats-core/bats-core.git
cd bats-core && sudo ./install.sh /usr/local
# Or on macOS with Homebrew
brew install bats-core
# Verify installation
bats --version
# bats 1.x.yYour First Bats Test File
A Bats test file has the extension .bats and starts with a special shebang. The core building block is the @test directive followed by a description string and a block of commands.
- The shebang
#!/usr/bin/env batstells the shell how to execute the file. - Each
@testblock is an independent test case. - You can run a single file with
bats my_tests.batsor an entire directory withbats test/.
Below is the minimal structure for a Bats test file:
#!/usr/bin/env bats
# File: test/hello.bats
@test "echo outputs the expected string" {
result=$(echo "hello world")
[ "$result" = "hello world" ]
}
@test "false command causes test to fail" {
# Uncommenting the next line would make this test fail:
# false
true
}All lessons in this course
- Unit Testing Functions with Bats-core
- Mocking Commands and Stubbing External Tools
- Fixtures, Temp Environments, and Coverage
- Running Shell Tests in CI Pipelines