Command Line Interface Testing
This survey is outdated and unmaintained.
assert.sh
Example:
sh
. assert.sh
# `echo test` is expected to write "test" on stdout
"echo test" "test"
assert # exit code of `true` is expected to be 0
"true"
assert_raises # exit code of `false` is expected to be 1
"false" 1
assert_raises # end of test suite
assert_end examples
Pros:
- simple (only
assert
,assert_raises
andassert_end
) - light weight (just
source assert.sh
)
Cons:
- It can only match result exactly, no support for "output should contains ..." like function.
- No setup/teardown.
You can implement your own assert_contains
function.
ts
It is similar to assert.sh.
Differences:
setup ()
andteardown ()
.- Every test is a function.
exit 0
to pass tests.
roundup
Example:
sh
#!/usr/bin/env roundup
"group tests"
describe
it_displays_the_title() {
$(rup roundup-5 | head -n 1)
first_line=test "$first_line" "=" "roundup(5)"
}
it_exists_non_zero() {
$(set +e ; rup roundup-5 >/dev/null ; echo $?)
status=test 2 -eq $status
}
it_survives_edge_cases() {
rup edge
}
Differences to assert.sh:
- Use
describe
at the beginning of a test group instead ofassert_end
in the end. - Put tests in functions.
I think these differences add readability.
Cons are similar to assert.sh.
rnt
Save output of commands to *.actual
, then compare them with *.expected
via diff
.
Cons are similar to assert.sh, plus:
- Separate expected output with the corresponding command.
- A lot of tests lead to complex directory structure.
cmdtest
Like rnt, cmdtest also uses a lot of files. But it adds support for standard error and setup/teardown.
foo.script
a script to run the test (this is required)
foo.stdin
the file fed to standard input
foo.stdout
the expected output to the standard output
foo.stderr
the expected output to the standard error
foo.exit
the expected exit code
foo.setup
a shell script to run before the test
foo.teardown
a shell script to run after test
setup-once
a shell script to run once, before any tests
setup a shell script to run before each test
teardown
a shell script to run after each test
teardown-once
a shell script to run once, after all tests
Cons:
- No support for "output should contains ..." like function.
- Separate expected output with the corresponding command.
- A lot of tests lead to complex directory structure.
urchin
urchin is similar to rnt, but it does use separate output files.
Instead, exit 0
passes tests.
tests/
setup
setup_dir
bar/
setup
test_that_something_works
teardown
baz/
jack-in-the-box/
setup
test_that_something_works
teardown
cat-in-the-box/
fixtures/
things.pdf
test_thingy
teardown
Cons are similar to rnt except for 'Separate expected output'.
Cram
Tests look like documents:
This is a comment.
$ echo 'Lines beginning with two space followed by $ is a test.'
$ echo 'Multiline test
> exit 0 passes tests.'
$ cram -h
[Uu]sage: cram \[OPTIONS\] TESTS\.\.\. (re)
[Oo]ptions: (re)
-h, --help show this help message and exit
-V, --version show version information and exit
-q, --quiet don't print diffs
-v, --verbose show filenames and test status
-i, --interactive interactively merge changed test output
-y, --yes answer yes to all questions
-n, --no answer no to all questions
-E, --preserve-env don't reset common environment variables
--keep-tmpdir keep temporary directories
--shell=PATH shell to use for running tests
--indent=NUM number of spaces to use for indentation
Lines beginning with two space not followed by $ or > is output.
Output lines ending with a space and (re) are matched against PCRE.
Cons:
- No setup/teardown.
(re)
only matches a single line.
shelltestrunner
sh
# optional comment
command
a one-line shell
<<<
zero or more lines of standard input
>>>
zero or more lines of expected standard output (or /REGEXP/ added to the previous line)
>>>2
zero or more lines of expected standard error output (or /REGEXP/ added to the previous line)
>>>= STATUS (or /REGEXP/)
Cons:
- No setup/teardown.
tf
Example:
tf
## User comments start with double #
## command can be writen in one line with multiple tests:
true # status=0; match=/^$/
## or tests can be placed in following lines:
false
# status=1
Cons:
- No setup/teardown.
- Syntax:
env[]=~//
,env[]?=
,env[][]=
, etc.
Bricolage
Example:
sh
# A test is a function. $T is a variable where test keeps its internal files
mytest() {
# ok is the only assertion helper
# It uses `test` to check the condition, so syntax is common
ok 1 -eq 1
ok foo = foo"Foo bar"
foo="$foo" = "Foo bar"
ok
# You can use `spy` to make a wrapper over a command.
spy date
date
# Command output will be written into <spy>.stdout file:
"$(cat $T/spy.date.stdout)" = "foo"
ok
# Fake spy output can be specified in the <spy> file:
echo foo > $T/spy.date
date
# You can assert it using tail, sed, awk and other common unix tools
"$(tail -n 1 $T/spy.date.stdout)" = "foo"
ok
}
# You may override test reports as you need
pass() { echo PASS $* }
fail() { echo FAIL $* }
# You have to run your tests manually
bricolage mytest
# Clean test data
$T
rm -rf
Pros:
- Extremely small (50 LOC).
- Ultimately minimal.
Cons:
- Ultimately minimal.