-
Notifications
You must be signed in to change notification settings - Fork 3
Bash: Unit Testing
Without a doubt, we discovered writing bash functions to be very simple - testing them for "the long haul" much more challenging. Our "knee-jerk" reaction was to write "one off" tests - but that doesn't ensure our quality should we need to make changes. With that said, we've provided a test harness vary similar in nature to JUnit in what we call the test-utils.sh framework. If you are familiar with JUnit this should "hopefully" be obvious. We do unit test (or try to) all our functions as can be found here.
Asserts allow one to test certain conditions and fail if those conditions are not met (as in exit with a 1
as the status code). Assert function names will resemble the intent and can be found in the script test-utils.sh.
This function accepts two parameters and ensures those parameters are equal.
# Will fail (exit code 1)
assert-equals "foo bar" "alpha beta"
# Will pass (exit code 0)
assert-equals "theta force" "theta force"
# Pass/fail depends on the values of ${foo} and ${bar}
assert-equals "${foo}" "${bar}"
This function accepts two parameters and ensures those parameters are not equal.
# Will pass (exit code 0)
assert-not-equals "foo bar" "alpha beta"
# Will fail (exit code 1)
assert-not-equals "theta force" "theta force"
# Pass/fail depends on the values of ${foo} and ${bar}
assert-not-equals "${foo}" "${bar}"
This function accepts 1 parameter and ensures it is blank (empty string).
# Will pass (exit code 0)
assert-blank ""
# Will fail (exit code 1)
assert-blank " "
# Pass/fail depends on the values of ${foo}
assert-blank "${foo}"
This function accepts 1 parameter and ensures it is not blank (empty string).
# Will pass (exit code 0)
assert-not-blank ""
# Will fail (exit code 1)
assert-not-blank " "
assert-not-blank "Hello world"
# Pass/fail depends on the values of ${foo}
assert-blank "${foo}"
This function accepts 1 parameter and ensures a file exists. If the parameter is blank, it will fail.
# Will pass (exit code 0)
rm /tmp/foo
assert-file-not-exists /tmp/foo
# Will fail (exit code 1)
touch /tmp/foo
assert-file-not-exists /tmp/foo
# Will fail as the param is blank
assert-file-not-exists ""
# Pass/fail depends on the values of ${foo}
assert-file-not-exists "${foo}"
This function accepts 1 parameter and ensures a file exists. If the parameter is blank, it will fail.
# Will pass (exit code 0)
touch /tmp/foo
assert-file-exists /tmp/foo
# Will fail (exit code 1)
rm /tmp/foo
assert-file-exists /tmp/foo
# Will fail as this is a dir
assert-file-exists /tmp
# Will fail as the param is blank
assert-file-exists ""
# Pass/fail depends on the values of ${foo}
assert-file-exists "${foo}"
This function considers all parameters as something to execute and examines the exit code for success (an exit code of 0
is success).
myTestFunction {
if [ $# -lt 1]
then
exit 1
elif [ -d $1 ]
then
exit 0
fi
exit 1
}
# Will pass (exit code 0)
mkdir /tmp/foo
assert-sucess myTestFunction /tmp/foo
# Will fail (exit code 1)
rmdir /tmp/foo
assert-success myTestFunction /tmp/foo
# Will fail (exit code 1)
assert-success myTestFunction
This function considers all parameters as something to execute and examines the exit code for failure (an exit code other than 0
is a failure that translates to this function returning success).
myTestFunction() {
if [ $# -lt 1]
then
exit 1
elif [ -d $1 ]
then
exit 0
fi
exit 1
}
# Will fail (exit code 1)
mkdir /tmp/foo
assert-failure myTestFunction /tmp/foo
# Will pass (exit code o)
rmdir /tmp/foo
assert-failure myTestFunction /tmp/foo
# Will pass (exit code 0)
assert-failure myTestFunction
A unit test represents a functional test to prove or disprove something works as designed. Should your code change, either the unit test will continue to pass or the unit test itself may require a change.
This function performs a unit test and expects the test to succeed with an exit code of 0
.
test-file-exists-for-success() {
touch /tmp/tmp-foo
assert-file-exists /tmp/tmp-foo
rm /tmp/tmp-foo
assert-file-not-exists /tmp/tmp-foo
}
test-file-exists-for-failure() {
rm /tmp/tmp-foo
assert-file-exists /tmp/tmp-foo
}
# Will pass
unit-test-should-pass test-file-exists-for-success
# Will fail
unit-test-should-pass test-file-exists-for-failure
This function performs a unit test and expects the test to fail with an exit code of 1
.
test-file-exists-for-success() {
touch /tmp/tmp-foo
assert-file-exists /tmp/tmp-foo
rm /tmp/tmp-foo
assert-file-not-exists /tmp/tmp-foo
}
test-file-exists-for-failure() {
rm /tmp/tmp-foo
assert-file-exists /tmp/tmp-foo
}
# Will fail
unit-test-should-pass test-file-exists-for-failure
# Will pass
unit-test-should-fail test-file-exists-for-success
There are times when one needs work performed before a unit test is run. Simply provide a function entitled unit-test-setup
and it will be run before each unit test.
unit-test-setup() {
export TEMP_DIR=/tmp/${USER}/`date +%N`
mkdir -p ${TEMP_DIR}
}
This will ensure a temporary directory is created for a user and store the name of the directory created in the variable entitled ${TEMP_DIR}
.
There are times when one needs work performed after a unit test is run. Simply provide a function entitled unit-test-teardown
and it will be run after each unit test.
unit-test-teardown() {
rm -rf ${TEMP_DIR}
}
Using the above unit-test-setup()
example, after each unit test is run, the created temporary directory will be removed.
A test suite represents a collection of unit tests that should be executed. Simply provide a script containing the function run-test-suite()
and pass to the script test-suite.sh.
The functions defined in this section should not be overridden.
This function emits some informational output as a unit test is executing. Additionally, it calls:
-
unit-test-setup
: executed before a unit test runs. -
unit-test-teardown
: executed after a unit test runs.
This function emits an informational message that testing is executing as well as defines global variables for total failed and passed tests. Additionally, it calls:
-
test-suite-setup
: executed before a test suite runs.
This function emits an information message about the number of passed and failed tests. If there are any failures, exits with a status code of 1. Additionally, it calls:
-
test-suite-teardown
: executed after a test suite runs.
The following unit tests have high test coverage: