Bash-TAP allows you to perform TAP-compliant tests within bash
using a similar test syntax to Perl's Test::More and Test::Builder,
suitable to run with prove
or any other TAP-consuming test harness.
For more information about TAP (the Test Anything Protocol) visit: http://testanything.org/
- Install the bash-tap files somewhere convenient for you.
The default location of
../../bash-tap
relative to your test files is the easiest zero-conf way, but you can set the$BASH_TAP_ROOT
environment variable if you want to install elsewhere. - If you're writing tests then copy
bash-tap-bootstrap
into your tests dir and source it inside your tests with:
. $(dirname $0)/bash-tap-bootstrap
- Run your tests with
prove my_test_dir
or your favourite TAP-consuming test harness, or run them manually as a script if you just want to see the raw TAP output.
Here's example test file 01_read_rows_from_key_value_lines.t
from
https://github.com/illusori/bash-snippets
#!/bin/bash
. $(dirname $0)/bash-tap-bootstrap
. $(dirname $0)/../read_rows_from_key_value_lines
columns_per_row=6
max_rows_per_rowset=3
total_rowsets=2
plan tests $(((columns_per_row * max_rows_per_rowset * total_rowsets) + total_rowsets))
# Test data, resultset 1
results1="artist Assemblage 23
track Naked (God Module RMX)
album Addendum
year 2001
rating 80
tracktime 5:22
artist Ayria
track Sapphire
album Debris
year
rating 100
tracktime 6:14
artist Apoptygma Berzerk
track Kathy's Song
album Welcome To Earth \"Extra bit for testing\"
year
rating 100
tracktime 6:35"
# Test data, resultset 2
results2="artist Colony 5
track The Bottle
album Lifeline
year
rating 80
tracktime 4:34"
output=$(_read_rows_from_key_value_lines "track" "$results1" 2>&1)
is "$output" "" "Read of rowset 1 should produce no output"
# Since $() runs in a subshell, we need to run it "for real" now
_read_rows_from_key_value_lines "track" "$results1" &>/dev/null
# Track 1
is "${track_artist[0]}" "Assemblage 23" "rowset 1 track 1 artist"
is "${track_track[0]}" "Naked (God Module RMX)" "rowset 1 track 1 track"
is "${track_album[0]}" "Addendum" "rowset 1 track 1 album"
is "${track_year[0]}" "2001" "rowset 1 track 1 year"
is "${track_rating[0]}" "80" "rowset 1 track 1 rating"
is "${track_tracktime[0]}" "5:22" "rowset 1 track 1 tracktime"
# Track 2
is "${track_artist[1]}" "Ayria" "rowset 1 track 2 artist"
is "${track_track[1]}" "Sapphire" "rowset 1 track 2 track"
is "${track_album[1]}" "Debris" "rowset 1 track 2 album"
is "${track_year[1]}" "" "rowset 1 track 2 year"
is "${track_rating[1]}" "100" "rowset 1 track 2 rating"
is "${track_tracktime[1]}" "6:14" "rowset 1 track 2 tracktime"
# Track 3
is "${track_artist[2]}" "Apoptygma Berzerk" "rowset 1 track 3 artist"
is "${track_track[2]}" "Kathy's Song" "rowset 1 track 3 track"
is "${track_album[2]}" "Welcome To Earth \"Extra bit for testing\"" "rowset 1 track 3 album"
is "${track_year[2]}" "" "rowset 1 track 3 year"
is "${track_rating[2]}" "100" "rowset 1 track 3 rating"
is "${track_tracktime[2]}" "6:35" "rowset 1 track 3 tracktime"
output=$(_read_rows_from_key_value_lines "track" "$results2" 2>&1)
is "$output" "" "Read of rowset 2 should produce no output"
# Since $() runs in a subshell, we need to run it "for real now
_read_rows_from_key_value_lines "track" "$results2" &>/dev/null
# Track 1
is "${track_artist[0]}" "Colony 5" "rowset 2 track 1 artist"
is "${track_track[0]}" "The Bottle" "rowset 2 track 1 track"
is "${track_album[0]}" "Lifeline" "rowset 2 track 1 album"
is "${track_year[0]}" "" "rowset 2 track 1 year"
is "${track_rating[0]}" "80" "rowset 2 track 1 rating"
is "${track_tracktime[0]}" "4:34" "rowset 2 track 1 tracktime"
# Track 2
is "${track_artist[1]}" "" "rowset 2 track 2 artist"
is "${track_track[1]}" "" "rowset 2 track 2 track"
is "${track_album[1]}" "" "rowset 2 track 2 album"
is "${track_year[1]}" "" "rowset 2 track 2 year"
is "${track_rating[1]}" "" "rowset 2 track 2 rating"
is "${track_tracktime[1]}" "" "rowset 2 track 2 tracktime"
# Track 3
is "${track_artist[2]}" "" "rowset 2 track 3 artist"
is "${track_track[2]}" "" "rowset 2 track 3 track"
is "${track_album[2]}" "" "rowset 2 track 3 album"
is "${track_year[2]}" "" "rowset 2 track 3 year"
is "${track_rating[2]}" "" "rowset 2 track 3 rating"
is "${track_tracktime[2]}" "" "rowset 2 track 3 tracktime"
Running this gives output:
$ prove ~/projects/bash-snippets/t
/Users/illusori/projects/bash-snippets/t/01_read_rows_from_key_value_lines.t .. ok
All tests successful.
Files=1, Tests=38, 0 wallclock secs ( 0.04 usr 0.00 sys + 0.04 cusr 0.02 csys = 0.10 CPU)
Result: PASS
Or the verbose output:
$ prove -v ~/projects/bash-snippets/t
/Users/illusori/projects/bash-snippets/t/01_read_rows_from_key_value_lines.t ..
1..38
ok 1 - Read of rowset 1 should produce no output
ok 2 - rowset 1 track 1 artist
ok 3 - rowset 1 track 1 track
ok 4 - rowset 1 track 1 album
ok 5 - rowset 1 track 1 year
ok 6 - rowset 1 track 1 rating
ok 7 - rowset 1 track 1 tracktime
ok 8 - rowset 1 track 2 artist
ok 9 - rowset 1 track 2 track
ok 10 - rowset 1 track 2 album
ok 11 - rowset 1 track 2 year
ok 12 - rowset 1 track 2 rating
ok 13 - rowset 1 track 2 tracktime
ok 14 - rowset 1 track 3 artist
ok 15 - rowset 1 track 3 track
ok 16 - rowset 1 track 3 album
ok 17 - rowset 1 track 3 year
ok 18 - rowset 1 track 3 rating
ok 19 - rowset 1 track 3 tracktime
ok 20 - Read of rowset 2 should produce no output
ok 21 - rowset 2 track 1 artist
ok 22 - rowset 2 track 1 track
ok 23 - rowset 2 track 1 album
ok 24 - rowset 2 track 1 year
ok 25 - rowset 2 track 1 rating
ok 26 - rowset 2 track 1 tracktime
ok 27 - rowset 2 track 2 artist
ok 28 - rowset 2 track 2 track
ok 29 - rowset 2 track 2 album
ok 30 - rowset 2 track 2 year
ok 31 - rowset 2 track 2 rating
ok 32 - rowset 2 track 2 tracktime
ok 33 - rowset 2 track 3 artist
ok 34 - rowset 2 track 3 track
ok 35 - rowset 2 track 3 album
ok 36 - rowset 2 track 3 year
ok 37 - rowset 2 track 3 rating
ok 38 - rowset 2 track 3 tracktime
ok
All tests successful.
Files=1, Tests=38, 0 wallclock secs ( 0.04 usr 0.01 sys + 0.04 cusr 0.02 csys = 0.11 CPU)
Result: PASS
Also included in bash-tap
is a simple function mocking framework
bash-tap-mock
, it lets you mock commands and functions with
mock_command
and restore_mocked_command
.
If you particularly care to only mock functions rather than commands
(a good safeguard against typos), use mock_function
and
restore_mocked_function
, which have some extended error checking
ensuring the function you're mocking exists in the first place.
An example from https://github.com/illusori/bash-itunes is clearer:
#!/bin/bash
. $(dirname $0)/bash-tap-bootstrap
. "$BASH_TAP_ROOT/bash-tap-mock"
. $(dirname $0)/../itunes
plan tests 4
sent_command=''
function mock_osascript() {
sent_command="$*"
restore_mocked_function "_osascript"
}
mock_function "_osascript" "mock_osascript"
start_output_capture
_dispatch "stop"
finish_output_capture stdout stderr
like "$sent_command" 'stop' "sent command should contain 'stop'"
like "$sent_command" 'tell application "iTunes"' "sent command should contain 'tell application \"iTunes\"'"
is "$stdout" "Stopping iTunes." "stdout should tell user what happened"
is "$stderr" "" "stderr should be empty"