Release 0.35.0
New features
Configurable spies
bashunit::spy now accepts an optional exit code or a custom implementation function so spies can simulate real behavior, not just record calls:
function test_spy_with_exit_code() {
spy curl 1
curl https://example.com
assert_general_spy_called_times "curl" 1
assert_equals 1 "$?"
}function fake_curl() {
echo "stubbed body"
return 0
}
function test_spy_with_impl() {
spy curl fake_curl
result=$(curl https://example.com)
assert_equals "stubbed body" "$result"
}Custom failure labels on assertions
Every assertion now accepts an optional trailing label that overrides the failure title, making failure output much easier to scan (#77):
function test_user_is_admin() {
assert_equals "admin" "$role" "user role mismatch"
assert_contains "@" "$email" "email format"
}Fail on risky tests
Risky tests (zero assertions) were introduced in 0.34.1 as warnings only. Use --fail-on-risky or BASHUNIT_FAIL_ON_RISKY=true to promote them to hard failures so silently empty tests cannot ship green (#115):
bashunit --fail-on-risky tests/GitHub Actions inline annotations
The new --log-gha <file> flag (or BASHUNIT_LOG_GHA) emits GitHub Actions workflow commands so failed, risky and incomplete tests appear as inline PR annotations (#280):
- name: Run tests
run: ./bashunit --log-gha gha.log tests/assert_exec for interactive commands and partial output
assert_exec gained five flags to feed stdin and assert on substrings of stdout/stderr, perfect for testing interactive prompts (#301):
--stdinto pipe input into the command--stdout-contains,--stdout-not-contains--stderr-contains,--stderr-not-contains
function test_prompt_accepts_yes() {
assert_exec \
--stdin "yes" \
--stdout-contains "Confirmed" \
./scripts/confirm.sh
}Changes
- Parallel test execution is now enabled on Alpine Linux (#370).
Bug fixes
- Dim/faint labels render as gray (SGR 90) so keywords like
ExpectedandTests:stay colored in GitHub Actions logs (#323). - Syntax error in a test file now fails the suite instead of passing silently (#220).
--stop-on-failurenow stops on runtime errors such ascommand not foundorillegal option(#383).- Spying on
echoorprintfno longer hangs via infinite recursion (#607). - LCOV and HTML coverage reports no longer produce empty output under
set -e(#618). clock::nowhandlesEPOCHREALTIMEvalues that use a comma decimal separator.- Invalid
.env.examplecoverage threshold entry fixed; CI now copies.env.exampleto.envso config parse errors are caught. - Coverage no longer counts case patterns with trailing comments (e.g.
*thing) # note) or loop terminators with redirections/pipes (e.g.done < file,done <<<"$var",done | sort) as executable lines (#634). assert_trueandassert_falsenow report empty strings as assertion failures instead of trying to execute them.
See the full changelog for 0.35.0 on GitHub.