Unit testing for shell scripts

Viewed 66375

Pretty much every product I've worked on over the years has involved some level of shell scripts (or batch files, PowerShell etc. on Windows). Even though we wrote the bulk of the code in Java or C++, there always seemed to be some integration or install tasks that were better done with a shell script.

The shell scripts thus become part of the shipped code and therefore need to be tested just like the compiled code. Does anyone have experience with some of the shell script unit test frameworks that are out there, such as shunit2 ? I'm mainly interested in Linux shell scripts for now; I'd like to know how well the test harness duplicate the functionality and ease of use of other xUnit frameworks, and how easy it is to integrate with continuous build systems such as CruiseControl or Hudson.

7 Answers

UPDATE 2019-03-01: My preference is bats now. I have used it for a few years on small projects. I like the clean, concise syntax. I have not integrated it with CI/CD frameworks, but its exit status does reflect the overall success/failure of the suite, which is better than shunit2 as described below.


PREVIOUS ANSWER:

I'm using shunit2 for shell scripts related to a Java/Ruby web application in a Linux environment. It's been easy to use, and not a big departure from other xUnit frameworks.

I have not tried integrating with CruiseControl or Hudson/Jenkins, but in implementing continuous integration via other means I've encountered these issues:

  • Exit status: When a test suite fails, shunit2 does not use a nonzero exit status to communicate the failure. So you either have to parse the shunit2 output to determine pass/fail of a suite, or change shunit2 to behave as some continuous integration frameworks expect, communicating pass/fail via exit status.
  • XML logs: shunit2 does not produce a JUnit-style XML log of results.

I recently released new testing framework called shellspec.

shellspec is BDD style testing framework. It's works on POSIX compatible shell script including bash, dash, ksh, busybox etc.

Of course, the exit status reflects the result of running of the specs and it's has TAP-compliant formatter.

The specfile is close to natural language and easy to read, and also it's shell script compatible syntax.

#shellcheck shell=sh

Describe 'sample'
  Describe 'calc()'
    calc() { echo "$(($*))"; }

    It 'calculates the formula'
      When call calc 1 + 2
      The output should equal 3
    End
  End
End

You should try out the assert.sh lib, very handy, easy to use

local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent! 

I have recently encountered a very thorough review of existing Bash unit testing frameworks - https://github.com/dodie/testing-in-bash

Shellspec has been so far the best, however it still depends on what you would like to achieve.

Related