Command line
bashunit uses a subcommand-based CLI. Each command has its own options and behavior.
Quick Reference
bashunit test [path] [options] # Run tests (default)
bashunit bench [path] [options] # Run benchmarks
bashunit watch [path] [options] # Watch files, re-run tests on change
bashunit assert <fn> <args> # Run standalone assertion
bashunit doc [filter] # Show assertion documentation
bashunit init [dir] # Initialize test directory
bashunit learn # Interactive tutorial
bashunit upgrade # Upgrade to latest version
bashunit --help # Show help
bashunit --version # Show versionArgument Notation
| Syntax | Meaning |
|---|---|
<arg> | Required - must be provided |
[arg] | Optional - can be omitted (uses default) |
test
bashunit test [path] [options]bashunit [path] [options]
Run test files. This is the default command - you can omit test for convenience.
# Run all tests in directory
bashunit test tests/
# Shorthand (same as above)
bashunit tests/
# Run specific test file
bashunit test tests/unit/example_test.sh
# Run with filter
bashunit test tests/ --filter "user"
# Run with options
bashunit test tests/ --parallel --simpleTest Options
| Option | Description |
|---|---|
-a, --assert <fn> <args> | Run a standalone assert function |
-e, --env, --boot <file> | Load custom env/bootstrap file (supports args) |
-f, --filter <name> | Only run tests matching name |
--tag <name> | Only run tests with matching @tag (repeatable) |
--exclude-tag <name> | Skip tests with matching @tag (repeatable) |
--output <format> | Output format (tap for TAP version 13) |
-w, --watch | Watch files and re-run tests on change |
--log-junit <file> | Write JUnit XML report |
--log-gha <file> | Write GitHub Actions workflow-commands log |
-j, --jobs <N> | Run tests in parallel with max N concurrent jobs |
-p, --parallel | Run tests in parallel |
--no-parallel | Run tests sequentially |
-r, --report-html <file> | Write HTML report |
-R, --run-all | Run all assertions (don't stop on first failure) |
-s, --simple | Simple output (dots) |
--detailed | Detailed output (default) |
-S, --stop-on-failure | Stop on first failure |
--show-skipped | Show skipped tests summary at end |
--show-incomplete | Show incomplete tests summary at end |
-vvv, --verbose | Show execution details |
--debug [file] | Enable shell debug mode |
--no-output | Suppress all output |
--failures-only | Only show failures |
--fail-on-risky | Treat risky tests (no assertions) as failures |
--no-progress | Suppress real-time progress, show only summary |
--show-output | Show test output on failure (default) |
--no-output-on-failure | Hide test output on failure |
--strict | Enable strict shell mode |
--skip-env-file | Skip .env loading, use shell environment only |
-l, --login | Run tests in login shell context |
--no-color | Disable colored output |
--coverage | Enable code coverage tracking |
--coverage-paths <paths> | Paths to track (default: auto-discover) |
--coverage-exclude <pat> | Exclusion patterns |
--coverage-report [file] | LCOV output path (default: coverage/lcov.info) |
--coverage-report-html [dir] | Generate HTML report (default: coverage/html) |
--coverage-min <percent> | Minimum coverage threshold |
--no-coverage-report | Console output only, no LCOV file |
Standalone Assert
bashunit test -a|--assert function "arg1" "arg2"
Run a core assert function standalone without a test context.
bashunit test --assert equals "foo" "bar"✗ Failed: Main::exec assert
Expected 'foo'
but got 'bar'Filter
bashunit test -f|--filter "test name"
Run only tests matching the given name.
bashunit test tests/ --filter "user_login"Tags
bashunit test --tag <name>bashunit test --exclude-tag <name>
Filter tests by # @tag annotations. Both flags are repeatable. --tag uses OR logic across names; --exclude-tag wins when a test matches both.
# @tag slow
function test_heavy_computation() {
...
}
# @tag integration
function test_api_call() {
...
}bashunit test tests/ --tag slow
bashunit test tests/ --tag slow --tag integration
bashunit test tests/ --exclude-tag integrationOutput format
bashunit test --output <format>
Select an alternative output format. Currently supported:
tap— TAP version 13 for CI/CD integrations.
The TAP version 13 header comes first, each test file is announced via a # <path> diagnostic line, each test emits an ok <n> - <name> or not ok <n> - <name> line (failures include a YAML --- ... ... block with expected/actual), and the 1..N plan line closes the report.
bashunit test tests/ --output tapTAP version 13
# tests/example_test.sh
ok 1 - Should validate input
not ok 2 - Should handle errors
---
Expected 'foo'
but got 'bar'
...
1..2Watch mode
bashunit test -w|--watch
Watch the test path (plus src/ if present) and re-run tests when files change. The -w/--watch flag uses a lightweight checksum polling loop that works on any system — no external tools required.
bashunit test tests/ --watchTIP
For file-event-driven watching (no polling), use the dedicated watch subcommand, which relies on inotifywait (Linux) or fswatch (macOS).
Environment / Bootstrap
bashunit test -e|--env|--boot <file>bashunit test --env "file arg1 arg2"
Load a custom environment or bootstrap file before running tests.
bashunit test --env tests/bootstrap.sh tests/# Pass arguments to the bootstrap file
bashunit test --env "tests/bootstrap.sh staging verbose" tests/Arguments are available as positional parameters ($1, $2, etc.) in your bootstrap script:
#!/usr/bin/env bash
# tests/bootstrap.sh
ENVIRONMENT="${1:-production}"
VERBOSE="${2:-false}"
export API_URL="https://${ENVIRONMENT}.api.example.com"You can also set arguments via environment variable:
BASHUNIT_BOOTSTRAP_ARGS="staging verbose" bashunit test tests/See Configuration: Bootstrap for more details.
Inline Filter Syntax
You can also specify a filter directly in the file path using :: or :line syntax:
Run a specific test by function name:
bashunit test path::function_name
bashunit test tests/unit/example_test.sh::test_user_login# Runs all tests containing "user" in their name
bashunit test tests/unit/example_test.sh::userRun the test at a specific line number:
bashunit test path:line_number
This is useful when jumping to a test from your editor or IDE.
bashunit test tests/unit/example_test.sh:42TIP
The line number syntax finds the test function that contains the specified line. If the line is before any test function, an error is shown.
Parallel
bashunit test -p|--parallelbashunit test --no-parallel
Run tests in parallel or sequentially. Sequential is the default.
In parallel mode, both test files and individual test functions run concurrently for maximum performance.
WARNING
Parallel mode is supported on macOS, Ubuntu, and Windows. On other systems (like Alpine Linux) the option is automatically disabled due to inconsistent results.
Opt-out of test-level parallelism
If a test file has shared state or race conditions, you can disable test-level parallelism by adding this directive as the second line:
#!/usr/bin/env bash
# bashunit: no-parallel-tests
function test_with_shared_state() {
# This test will not run in parallel with others in this file
}The file will still run in parallel with other files, but tests within it will run sequentially.
Jobs
bashunit test -j|--jobs <N>
Run tests in parallel with a maximum of N concurrent jobs. This implicitly enables parallel mode.
Use this to limit CPU usage on CI or machines with constrained resources.
bashunit test tests/ --jobs 4TIP
--jobs 0 (the default) means unlimited concurrency, which is equivalent to --parallel.
Output Style
bashunit test -s|--simplebashunit test --detailed
Choose between simple (dots) or detailed output.
bashunit test tests/ --simple........bashunit test tests/ --detailedRunning tests/unit/example_test.sh
✓ Passed: Should validate input
✓ Passed: Should handle errorsReports
Generate test reports in different formats:
bashunit test tests/ --log-junit results.xmlbashunit test tests/ --report-html report.htmlbashunit test tests/ --log-gha gha.log && cat gha.logThe --log-gha flag writes GitHub Actions workflow commands (::error, ::warning, ::notice) for failed, risky and incomplete tests. When streamed to stdout on a runner, they appear as inline annotations in the "Files changed" tab of a pull request.
Show Output on Failure
bashunit test --show-outputbashunit test --no-output-on-failure
Control whether test output (stdout/stderr) is displayed when tests fail with runtime errors or assertion failures.
By default (--show-output), when a test fails due to a runtime error (command not found, unbound variable, permission denied, etc.) or a failed assertion after the test printed diagnostics, bashunit displays the captured output in an "Output:" section to help debug the failure.
Use --no-output-on-failure to suppress this output.
bashunit test tests/ --no-output-on-failure✗ Error: My test function
command not found
Output:
Debug: Setting up test
Running command: my_command
/path/to/test.sh: line 5: my_command: command not foundNo Progress
bashunit test --no-progress
Suppress real-time progress display during test execution, showing only the final summary.
When enabled, bashunit hides:
- Per-test output (pass/fail messages or dots)
- File headers ("Running tests/...")
- Hook completion messages
- Spinner during parallel execution
The final summary with test counts and results is still displayed.
This is useful for:
- CI/CD pipelines where streaming output causes issues
- Log-restricted environments
- Reducing output noise when only the final result matters
bashunit test tests/ --no-progressbashunit - 0.34.1 | Tests: 10
Tests: 10 passed, 10 total
Assertions: 25 passed, 25 total
All tests passed
Time taken: 1.23sStrict Mode
bashunit test --strict
Enable strict shell mode (set -euo pipefail) for test execution.
By default, tests run in permissive mode which allows:
- Unset variables without errors
- Non-zero return codes from commands
- Pipe failures to be ignored
With --strict, your tests run with bash strict mode enabled, catching potential issues like uninitialized variables and unchecked command failures.
bashunit test tests/ --strictSkip Env File
bashunit test --skip-env-file
Skip loading the .env file and use the current shell environment only.
By default, bashunit loads variables from .env which can override environment variables set in your shell. Use --skip-env-file when you want to:
- Run in CI/CD where environment is pre-configured
- Override
.envvalues with shell environment variables - Avoid
.envinterfering with your current settings
Important
Only environment variables are inherited from the parent shell. Shell functions and aliases are NOT available in tests due to bashunit's subshell architecture. Use a bootstrap file to define functions needed by your tests.
BASHUNIT_SIMPLE_OUTPUT=true ./bashunit test tests/ --skip-env-fileLogin Shell
bashunit test -l|--login
Run tests in a login shell context by sourcing profile files.
When enabled, bashunit sources the following files (if they exist) before each test:
/etc/profile~/.bash_profile~/.bash_login~/.profile
Use this when your tests depend on environment setup from login shell profiles, such as:
- PATH modifications
- Shell functions defined in
.bash_profile - Environment variables set during login
bashunit test tests/ --loginCoverage
bashunit test --coverage
Enable code coverage tracking for your tests. See the Coverage documentation for comprehensive details.
bashunit test tests/ --coveragebashunit test tests/ --coverage --coverage-paths src/,lib/ --coverage-min 80Coverage options:
| Option | Description |
|---|---|
--coverage | Enable coverage tracking |
--coverage-paths <paths> | Comma-separated paths to track (default: auto-discover from test files) |
--coverage-exclude <patterns> | Comma-separated patterns to exclude (default: tests/*,vendor/*,*_test.sh) |
--coverage-report [file] | LCOV output file path (default: coverage/lcov.info) |
--coverage-report-html [dir] | Generate HTML report (default: coverage/html) |
--coverage-min <percent> | Minimum coverage percentage; fails if below |
--no-coverage-report | Show console report only, don't generate LCOV file |
TIP
Coverage works with parallel execution (-p). Each worker tracks coverage independently, and results are aggregated before reporting.
bench
bashunit bench [path] [options]
Run benchmark functions prefixed with bench_. Use @revs and @its comments to control revolutions and iterations.
# Run all benchmarks
bashunit bench
# Run specific benchmark file
bashunit bench benchmarks/parser_bench.sh
# With filter
bashunit bench --filter "parse"Bench Options
| Option | Description |
|---|---|
-e, --env, --boot <file> | Load custom env/bootstrap file (supports args) |
-f, --filter <name> | Only run benchmarks matching name |
-s, --simple | Simple output |
--detailed | Detailed output (default) |
-vvv, --verbose | Show execution details |
--skip-env-file | Skip .env loading, use shell environment only |
-l, --login | Run in login shell context |
watch
bashunit watch [path] [test-options]
Dedicated watch subcommand that uses OS file-event notifications (no polling) to re-run tests as soon as a .sh file changes. Any option accepted by bashunit test is also accepted here.
# Watch current directory
bashunit watch
# Watch the tests/ directory
bashunit watch tests/
# Watch and filter by name
bashunit watch tests/ --filter user
# Watch with simple output
bashunit watch tests/ --simpleRequirements
- Linux:
inotifywait(sudo apt install inotify-tools) - macOS:
fswatch(brew install fswatch)
If the required tool is not installed, bashunit prints a clear installation hint and exits with a non-zero code.
TIP
If you cannot install inotifywait or fswatch, use the portable -w/--watch flag on bashunit test instead (uses polling).
doc
bashunit doc [filter]
Display documentation for assertion functions.
# Show all assertions
bashunit doc
# Filter by name
bashunit doc equals
# Show file-related assertions
bashunit doc file## assert_equals
--------------
> `assert_equals "expected" "actual"`
Reports an error if the two variables are not equal...
## assert_not_equals
--------------
...init
bashunit init [directory]
Initialize a new test directory with sample files.
# Create tests/ directory (default)
bashunit init
# Create custom directory
bashunit init spec> bashunit initialized in testsCreates:
bootstrap.sh- Setup file for test configurationexample_test.sh- Sample test file to get started
learn
bashunit learn
Start the interactive learning tutorial with 10 progressive lessons.
bashunit learnbashunit - Interactive Learning
Choose a lesson:
1. Basics - Your First Test
2. Assertions - Testing Different Conditions
3. Setup & Teardown - Managing Test Lifecycle
4. Testing Functions - Unit Testing Patterns
5. Testing Scripts - Integration Testing
6. Mocking - Test Doubles and Mocks
7. Spies - Verifying Function Calls
8. Data Providers - Parameterized Tests
9. Exit Codes - Testing Success and Failure
10. Complete Challenge - Real World Scenario
p. Show Progress
r. Reset Progress
q. Quit
Enter your choice:TIP
Perfect for new users getting started with bashunit.
upgrade
bashunit upgrade
Upgrade bashunit to the latest version.
bashunit upgrade> Upgrading bashunit to latest version
> bashunit upgraded successfully to latest version 0.34.1Global Options
These options work without a subcommand:
Version
bashunit --version
Display the current version.
bashunit --versionbashunit - 0.35.0Help
bashunit --help
Display help message with available commands.
bashunit --helpUsage: bashunit <command> [arguments] [options]
Commands:
test [path] Run tests (default command)
bench [path] Run benchmarks
assert <fn> <args> Run standalone assertion
doc [filter] Display assertion documentation
init [dir] Initialize a new test directory
learn Start interactive tutorial
watch [path] Watch files and re-run tests on change
upgrade Upgrade bashunit to latest version
Global Options:
-h, --help Show this help message
-v, --version Display the current version
Run 'bashunit <command> --help' for command-specific options.Each subcommand also supports --help:
bashunit test --help
bashunit bench --help
bashunit watch --help
bashunit doc --help