One of my scripts is trying to figure out if all it's dependencies are installed when there is an error. In order to do that I use the built-in command
. Let's assume the most limited version I could come up with (let's call that script_to_test.sh
:
command -v pdfgrep
return $?
Now I have a bats-core test file test.sh
:
setup() {
# See https://bats-core.readthedocs.io/en/stable/tutorial.html
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
# See https://github.com/buildkite-plugins/bats-mock
load 'test_helper/mocks/stub'
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR/..:$PATH"
}
@test "Test mocking built-ins" {
stub command \
"-v pdfgrep : exit 17"
run script_to_test.sh
unstub command
assert_failure 17
}
When I run that, I get:
`unstub command' failed
This is because the stubbed command
was never called.
Is it even possible to stub built-ins?
How can I test my scripts behavior where it depends on the environment?
As I know, it is not possible, because built-in commands are part of the shell itself, and they cannot be easily replaced or stubbed! but maybe I can explain it to you with another approach using an example, in my scenario instead of relying on the built-in command directly, you can create a wrapper function or script that encapsulates the behavior of the built-in command and after that, you can stub or mock this wrapper function/script in your tests, for example when you run test.sh
using Bats, it will execute the test case named Test mocking built-ins
. so,I stubbed the check_dependency
function to simulate the scenario where pdfgrep
is not installed and the test expects the script to fail with an exit code of 1
!
you can move the check_dependency function into its own separate file, let's say dependency_checker.sh
,and then source this file in both script_to_test.sh and test.sh so that they can access the function.
let me show you how:
dependency_checker.sh:
#!/bin/bash
check_dependency() {
command -v "$1" >/dev/null 2>&1
return $?
}
script_to_test.sh:
#!/bin/bash
source dependency_checker.sh
check_dependency pdfgrep
return $?
test.sh:
setup() {
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
load 'test_helper/mocks/stub'
DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR/..:$PATH"
}
@test "Test mocking built-ins" {
stub check_dependency \
"pdfgrep : return 1"
run script_to_test.sh
unstub check_dependency
assert_failure 1
}