View on GitHub

shellspec

BDD style unit testing framework for POSIX compatible shell script

Let’s test the your shell script!

shellspec is a BDD style unit testing framework for POSIX compatible shell script

Get started!

Features

Specfile syntax

Describe 'sample' # Example group
  Describe 'bc command'
    add() { echo "$1 + $2" | bc; }

    It 'performs addition' # Example
      When call add 2 3 # Evaluation
      The output should eq 5  # Expectation
    End
  End

  Describe 'implemented by shell function'
    Include ./mylib.sh # add() function defined

    It 'performs addition'
      When call add 2 3
      The output should eq 5
    End
  End
End

Why use shellspec?

1. It’s a BDD style

shellspec is a BDD style unit testing framework. You can write specifications with DSL that nearly to natural language. And also those DSL are structured and executable.

shellspec is created inspired by rspec, and it has a DSL suitable for shell scripts. And it’s a readability even if you are not familiar with shell scripts syntax.

Comparison with other unit testing frameworks.

Comparison with Bats

shellspec is less syntax of shell scripts specific, and you can write specification in sentences nearly to natural language.

bats

#!/usr/bin/env bats

@test "addition using bc" {
  result="$(echo 2+2 | bc)"
  [ "$result" -eq 4 ]
}

@test "addition using dc" {
  result="$(echo 2 2+p | dc)"
  [ "$result" -eq 4 ]
}

shellspec

#shellcheck shell=sh

Example "addition using bc"
  When call "echo 2+2 | bc"
  The output should eq 4
End

Example "addition using dc"
  When call "echo 2 2+p | dc"
  The output should eq 4
End
Comparison with shunit2

shUnit2 is a xUnit based unit test framework for Bourne based shell scripts.

shellspec has structured DSL and readability.

shunit2

#! /bin/sh
# file: examples/math_test.sh

testAdding() {
  result=`add_generic 1 2`
  assertEquals \
      "the result of '${result}' was wrong" \
      3 "${result}"

  # Disable non-generic tests.
  [ -z "${BASH_VERSION:-}" ] && startSkipping

  result=`add_bash 1 2`
  assertEquals \
      "the result of '${result}' was wrong" \
      3 "${result}"
}

oneTimeSetUp() {
  # Load include to test.
  . ./math.inc
}

# Load and run shUnit2.
. ./shunit2

shellspec

#shellcheck shell=sh

Describe 'Adding'
  Include ./math.inc

  Describe 'generic'
    Describe 'add_generic()'
      It 'adds values'
        When call add_generic 1 2
        The output should eq 3
      End
    End
  End

  Describe 'non-generic'
    Skip if 'non-generic tests' [ -z "${BASH_VERSION:-}" ]

    Describe 'add_bash()'
      It 'adds values'
        When call add_bash 1 2
        The output should eq 3
      End
    End
  End
End

2. Fast testing

If failed your tests, display error with the line number. You can re-run the failed tests with the line number.

If you want to run specific test only, you can use --focus option to run focused tests. (To focus, prepend ‘f’ to groups / examples in specfiles. e.g. Describe -> fDescribe, It -> fIt, etc.)

If you want to temporarily skip some tests, prepend ‘x’ to groups / examples in specfiles (like xDescribe, xIt, etc.)

And more, using parallel execution may increase speed running tests depending on your tests and the testing hardware. (but in my opinion it’s fast enough without parallel execution.)

Those feature are implemented only by shell script, so you can use it all shells. (Do not need $LINENO variable of shell, and not requires GNU parallel)

3. Modern reporting

shellspec has modern reporting similar like rspec. When specs fails, it reports expected and actual with line number and colored.

shellspec has three reporting formatter, progress, documentation, tap.

progress formatter (default)

documentation formatter

tap formatter

4. Implements by pure POSIX compatible shell scripts

shellspec is implements by 100% pure POSIX compatible shell scripts. The required external commands are basic few POSIX compliant commands only.

Not only bash, it supports dash, zsh, ksh, yash, posh and busybox ash. shellspec is written by POSIX compatible syntax, but you can use extended syntax of bash, etc.

It works on Linux (e.g Debian, Alpine Linux on Docker, OpenWrt), macOS, Unix (e.g. Solaris) and Windows Subsystem for Linux. Works in more environments.

5. The specfile is compatible with shell script syntax

The specfile looks like natural language, but also compatible with shell script syntax. therefore you can mixing shell script code in specfile and also checking syntax using by sh -n, shellcheck and so on.

The specfile is valid shell script syntax, but it extended. It supports nestable block, scope and temporary function redefinition for mock/stub.

Those features is realized by code translation. The block of DSL translate to subshell, it executes in own environment. This achieves isolation of tests.

6. And what you need

Besides, shellspec has the necessary features for unit testing.

shellspec is designed with an extensible architecture, so you can create custom matcher, custom modifier and so on.

shellspec is a powerful but simple to use. Let’s enjoy test with shellspec!