Introduction
Testing is an important component of the development process of Bash scripts that contributes to the final product’s quality.
In general, the test procedure consists of identifying core components of the target script and creating test cases that will verify the expected outcome is right. This process is iterative and must be executed every time the source code is changed.
Since creating and managing test cases can quickly become a challenge it’s recommended to adopt automated testing tools that can provide:
- bash functions for common test-patterns
- standard reporting formats
- integration with CI-CD tools
- integration with container engines
- test cases execution management
It’s also a best practice to separate test and dev environments by using purpose-built VMs or containers. This approach becomes crucial when working on scenarios that require the installation of additional OS packages and/or 3rd party applications, run privileged commands that can alter or destroy the environment, etc.
The “Testing bash scripts” document is a hands-on guide to exploring how to create, organize and run test cases using the bats-core and testmansh tools:
- bats-core: testing framework that provides bash functions for common test patterns and execution/reporting capabilities
- testmansh: test case manager that integrates shellcheck and bats-core with container-based testing
Organizing test cases
Let’s start with a simple folder structure used both for source and testing code:
Additional subdirectories can be created in tst_prj/test/
to group test cases by modules, services, test types, etc.
Preparing the test environment
Although optional, it’s highly recommended to use containers to run tests. Verify that docker
or podman
are installed in your machine and ready to run.
Deploy the testmansh tool to tst_prj/bin/
:
Now create the test target bash script:
|
|
Defining the test strategy
Before any test-case is created it’s advised to establish the testing scope. For example:
- scope: key script commands, key script functions, key functions from project-wide libraries
- out-of-scope: external bash libraries managed by their development process (e.g. OSS libraries, etc)
Once the general scope is defined identify what test cases are needed and the expected outcome:
test-case-1
: running theexample
script with no arguments should cancel execution and return exit status = 1test-case-2
: running theexample
script with the required argument should complete with exit status = 0test-case-3
: calling thetransform_to_lowercase
function with a mixed case parameter should print via STDOUT the same string converted to lowercasetest-case-4
: calling theshow_package_manager
function should print current package version via STDOUT
Understanding bats-core test-case syntax
The bats-core tool uses text files written in bash to define test cases.
Each file may contain one or more test cases with optional pre-test and post-test tasks:
|
|
Additional keywords are available to include in the test-case definition:
skip
: use to skip test-case execution without raising an errorrun
: use to execute external commands or functions and capture result in shell variables:status
: exit status of the executed command or functionoutput
: combined content of the command’s or function’s standard-output (STDOUT) and standard-error (STDERR)
Creating test cases
Let’s implement the first test-case: probe that running the script with no args will raise an error:
The second test-case will check that calling the script with the required argument runs successfully:
For the thirst test-case verify that the function transform_to_lowercase
successfully converts cases in 2 different scenarios:
|
|
Lastly, the fourth test-case will check that the function generates output (no matter what)
|
|
Running test cases
Now that all test cases are created let’s use the testmansh
tool to run them in purpose-build containers:
See below the execution report. All test cases passed successfully:
|
|
Since the function show_package_manager
depends on the OS, let’s see what happens in a different OS:
As expected the test fails because the function is incompatible with the target OS:
|
|
References
Copyright information
This article is licensed under a Creative Commons Attribution 4.0 International License. For copyright information on the product or products mentioned inhere refer to their respective owner.
Disclaimer
Opinions presented in this article are personal and belong solely to me, and do not represent people or organizations associated with me in a professional or personal way. All the information on this site is provided “as is” with no guarantee of completeness, accuracy or the results obtained from the use of this information.