Skip to content

Checksum/critic.sh

Repository files navigation

critic.sh

CI


Dead simple testing framework for Bash with coverage.

asciicast

git-cloc

Why?

I was looking for a Bash testing framework with a familiar API and with coverage reporting. Although there are excellent frameworks like bats-core, shunit2 and bashunit, I wasn't too comfortable with their API (not their fault). Also, I wanted some indication of coverage, so that it can be improved over time.

critic.sh exposes high level functions for testing consistent with other frameworks and a set of built in assertions. One of my most important goals was to be able to pass in any shell expression to the _test and _assert methods, so that one is not limited to the built-ins.

In addition, it can generate a lcov report. It tracks line and function coverage, but not branches. It works by running the tests with extended debugging, redirecting the trace output to a log file, and then parsing it to determine which functions/lines have been executed. It is currently a work in progress.

Requirements

Due to use of certain bashisms, Bash v4.1+ is required. This may change in the future.

A tiny docker image is provided for convenience.

Installation

There are a few ways to use critic.sh:

  • Use the docker image
docker run --rm -v $(pwd):/work checksum/critic.sh '/work/src/*.sh' '/work/lib/*.sh'

You can pass a CRITIC_SETUP environment variable to run setup scripts before the tests are run. The docker image is based on alpine linux, so use apk to install packages:

docker run --rm -e CRITIC_SETUP='apk add --no-cache jq' -v $(pwd):/work checksum/critic.sh '/work/src/*.sh' '/work/lib/*.sh'
  • Add this repository as a git submodule in your project
git submodule add https://github.com/Checksum/critic.sh critic
critic/critic.sh test.sh
  • Copy critic.sh file into your project (not recommended)

Usage

See examples/test.sh for detailed usage. To run the tests: bash examples/test.sh

Source the framework in your test file

# test-foobar.sh

# Include your source files
source foobar.sh
# Include the framework
source critic.sh

# Write tests
_describe foo
  _test "output should equal foo"
    _assert _output_equals "foo"

  _test "return code should be 0"
    _assert _return_true "Optional assertion message"

Pass the test file as an argument

critic.sh test-foobar.sh

API

The layout of a test is consistent with other frameworks. You _describe a test suite, _test a function or expression, and _assert the output with a function or expression. The output, return code and arguments passed to the test are available as variables for all custom assertions.

Test suite

Function Description Arguments
_describe Run test suite 1. Suite/Function name (*)
_describe_skip Skip this test suite 1. Suite/Function name (*)
_test Run a test 1. Test name (*)
2. Test function/expression
3. Arguments to forward to the test function
_test_skip Skip this test 1. Test name (*)
2. Test function/expression
3. Arguments to forward to the test function
_assert Run an assertion 1. Assertion function/expression (*)
2. Arguments to forward to the assertion function
_teardown Teardown function run after all tests have ben run

Assertions

Function Description Arguments
_return_true Return code == 0 1. Optional message
_return_false Return code != 0 1. Optional message
_return_equals Return code == num 1. Return code (*)
2. Optional message
_output_contains Output contains value 1. Value (*)
2. Optional message
_output_equals Output equals value 1. Value (*)
2. Optional message
_not Negate an assertion 1. Assertion (*)
2. Value (*)
3. Optional message
_nth_arg_equals Nth arg equals value 1. Argument index (>=0)
2. Value
3. Optional message

Variables

After every _test is run, the following variables are set. These are useful for custom assertions:

Variable Description
_output Output of the function/expression
_return Return code
_args Arguments passed to the function/expression

Options

Environment variable Description Default
CRITIC_COVERAGE_DISABLE Disable coverage false
CRITIC_COVERAGE_MIN_PERCENT Minimum coverage percent per source file 0
CRITIC_COVERAGE_REPORT_CLI Print coverage report to CLI true
CRITIC_COVERAGE_REPORT_LCOV Save lcov report true
CRITIC_COVERAGE_REPORT_HTML Generate HTML lcov report (requires lcov) false
CRITIC_DEBUG Prints more verbose messages false

Annotations

Disable coverage for certain lines by wrapping them in # critic ignore and # critic /ignore blocks:
# critic ignore
foo() {
  echo "This function will skipped when calculating coverage %"
}
# critic /ignore