While writing a test that expects an exception/error to be thrown, I am experiencing some difficulties detecting the error.
The code installs various software packages and tests each installation command separately. There is one function that does some preprocessing before each function and then calls the installation function, this managing function is called: run_main_functions
, and it passes along arguments if they are entered. For completenes, the code of run_main_functions
consists of:
#!/bin/bash
run_main_functions() {
local SCRIPT_NAME=$1
local EXTRA_ARGUMENT=$2
SCRIPT_PATH=src/"$SCRIPT_NAME".sh
local LOG_PATH=$LOG_LOCATION"$SCRIPT_NAME".txt
chmod +x $SCRIPT_PATH
# Remove old log files if exist
if [ -f "$LOG_PATH" ] ; then
rm "$LOG_PATH"
fi
# run the function that performs a single installation command
if [ "$EXTRA_ARGUMENT" == "" ]; then
source ./$SCRIPT_PATH $LOG_PATH
else
source ./$SCRIPT_PATH $LOG_PATH $EXTRA_ARGUMENT
fi
}
This run_main_functions
then calls a function count_nr_of_lines
which I expect to throw an error if it is fed an invalid filepath. It consists of:
#!/bin/bash
# Count the total nr of lines in an incoming file and export it.
count_nr_of_lines() {
source src/hardcoded_variables.txt
local LOG_PATH=$1
local INPUT_PATH=$2
# read content from file
text_content=$(<$INPUT_PATH)
# count the number of lines in that app
total_nr_of_lines=$(echo "$text_content" | wc -l)
# 4. Write the result of the content check to a log file.
echo $total_nr_of_lines > "${TOTAL_NR_OF_LINES_IN_TARGET_FILEPATH}"
}
count_nr_of_lines "$@"
And the test that checks whether the count_nr_of_lines
throws an error if the INPUT_PATH
is of a non-existant filepath is:
#!./test/libs/bats/bin/bats
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'libs/bats-file/load'
source test/helper.sh
source src/hardcoded_variables.txt
source src/helper.sh
mkdir -p src/logs
# Method that executes all tested main code before running tests.
setup() {
# print test filename to screen.
if [ "${BATS_TEST_NUMBER}" = 1 ];then
echo "# Testfile: $(basename ${BATS_TEST_FILENAME})-" >&3
fi
# Declare filenames of files that perform commands
declare -a script_names=("custom_install_4_energizedprotection")
# Specify an additional array with arguments
declare -a additional_arguments=("test/testfiles/nonexistant_filename.txt")
# Loop through files that perform commands
for i in "${!script_names[@]}"; do
run_main_functions "${script_names[i]}" "${additional_arguments[i]}"
done
}
#---------------------------------------------------------------------------------------------------------------------------
@test "Tests whether an exception is thrown when computing the total nr of lines, if the file is not found." {
ACTUAL_RESULT=$(<$TOTAL_NR_OF_LINES_IN_TARGET_FILEPATH)
EXPECTED_OUTPUT="1"
assert_failure
#assert_equal "$ACTUAL_RESULT" "$EXPECTED_OUTPUT"
}
Where the filepath to the non-existant file is fed as:"test/testfiles/nonexistant_filename.txt"
. The test fails with error:
ā Tests whether an exception is thrown when computing the total nr of lines, if the file is not found.
(from function `apt_update' in file ./src/custom_install_4_energizedprotection.sh, line 10,
from function `source' in file ./src/custom_install_4_energizedprotection.sh, line 18,
from function `run_main_functions' in file src/helper.sh, line 19,
from function `setup' in test file test/test_custom_install_4_1_energizedprotection.bats, line 28)
`run_main_functions "${script_names[i]}" "${additional_arguments[i]}"' failed
./src/custom_install_4_energizedprotection.sh: line 10: test/testfiles/nonexistant_filename.txt: No such file or directory
So in some sense, an error is thrown, which is expected, but I would expect the bats test to catch that error/exception, and yield a passed test
.
How could I make the bats
test pass succesfully by catching/registering the error that is thrown if the file does not exist?
I also tried to include an invalid path detection inside the count_nr_of_lines
function with:
if [ ! -f "$INPUT_PATH" ] ; then
exit 1
fi
to throw an explicit error, however, that removes the verbosity/error messages from the test failure and only results in a failing test.
I don't understand why you're running the test code in the setup. How about this
setup() {
# print test filename to screen.
if [ "${BATS_TEST_NUMBER}" = 1 ];then
echo "# Testfile: $(basename ${BATS_TEST_FILENAME})-" >&3
fi
}
#---------------------------------------------------------------------------------------------------------------------------
@test "Tests whether an exception is thrown when computing the total nr of lines, if the file is not found." {
#ACTUAL_RESULT=$(<$TOTAL_NR_OF_LINES_IN_TARGET_FILEPATH)
#EXPECTED_OUTPUT="1"
# this will report an error if it has a non-zero return status
run_main_functions "custom_install_4_energizedprotection" "test/testfiles/nonexistant_filename.txt"
#assert_equal "$ACTUAL_RESULT" "$EXPECTED_OUTPUT"
}
I missed the point that you are explicitly expecting failure. You could
! run_main_functions ...
which will error if run_main_functions returns OK, or use the run
command
run run_main_functions
expect_failure
which I think will work, but I have a vague recollection about having to export sourced functions (I can't find any reference about that in the docs though)
And after re-reading the docs, instead of setup
use setup_file
:
setup_file() {
echo "# Testfile: $(basename ${BATS_TEST_FILENAME})-" >&3
}