├── LICENSE ├── README.md ├── bashunit.bash └── test_example /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Uwe Dauernheim 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bashunit 2 | 3 | `bashunit` is a unit testing framework for Bash scripts based on xUnit principles. 4 | 5 | This is similar to the [ShUnit](http://shunit.sourceforge.net/) and its 6 | successor [shUnit2](https://code.google.com/p/shunit2/). 7 | 8 | ## Usage 9 | 10 | Functions starting with 'test' will be automatically evaluated. 11 | 12 | **1. Write test cases** 13 | 14 | ```bash 15 | testEcho() { 16 | assertEqual "$(echo foo)" "foo" 17 | assertReturn "$(echo foo)" 0 18 | } 19 | ``` 20 | 21 | **2. Include this script at the end of your test script** 22 | 23 | ```bash 24 | source $(dirname $0)/bashunit.bash 25 | 26 | # eof 27 | ``` 28 | 29 | **3. Run test suite** 30 | 31 | ```bash 32 | $ ./test_example 33 | testEcho:4:Passed 34 | testEcho:5:Passed 35 | Done. 2 passed. 0 failed. 0 skipped. 36 | ``` 37 | 38 | The return code is equal to the amount of failed testcases. 39 | 40 | Options can be given to the test script: 41 | 42 | ```bash 43 | $ bash ./bashunit.bash 44 | Usage: [options...] 45 | 46 | Options: 47 | -v, --verbose Print expected and provided values 48 | -s, --summary Only print summary omitting individual test results 49 | -q, --quiet Do not print anything to standard output 50 | -l, --lineshow Show failing or skipped line after line number 51 | -f, --failed Print only individual failed test results 52 | -h, --help Show usage screen 53 | ``` 54 | 55 | ## Dependencies 56 | 57 | * Bash (`BASH_LINENO`) 58 | * Shell colours 59 | 60 | ## API 61 | 62 | * `assert($1)` 63 | 64 | `$1`: Expression 65 | 66 | Assert that a given expression evaluates to true. 67 | 68 | * `assertEqual($1, $2)` 69 | 70 | `$1`: Output 71 | 72 | `$2`: Expected 73 | 74 | Assert that a given output string is equal to an expected string. 75 | 76 | * `assertNotEqual($1, $2)` 77 | 78 | `$1`: Output 79 | 80 | `$2`: Expected 81 | 82 | Assert that a given output string is not equal to an expected string. 83 | 84 | * `assertStartsWith($1, $2)` 85 | 86 | `$1`: Output 87 | 88 | `$2`: Expected 89 | 90 | Assert that a given output string starts with an expected string. 91 | 92 | * `assertReturn($1, $2)` 93 | 94 | `$1`: Output 95 | 96 | `$2`: Expected 97 | 98 | `$?`: Provided 99 | 100 | Assert that the last command's return code is equal to an expected integer. 101 | 102 | * `assertNotReturn($1, $2)` 103 | 104 | `$1`: Output 105 | 106 | `$2`: Expected 107 | 108 | `$?`: Provided 109 | 110 | Assert that the last command's return code is not equal to an expected 111 | integer. 112 | 113 | * `assertGreaterThan($1, $2)` 114 | 115 | `$1` Output 116 | 117 | `$2` Expected 118 | 119 | Assert that a given integer is greater than an expected integer. 120 | 121 | * `assertAtLeast($1, $2)` 122 | 123 | `$1` Output 124 | 125 | `$2` Expected 126 | 127 | Assert that a given integer is greater than or equal to an expected integer. 128 | 129 | * `assertLessThan($1, $2)` 130 | 131 | `$1` Output 132 | 133 | `$2` Expected 134 | 135 | Assert that a given integer is less than an expected integer. 136 | 137 | * `assertAtMost($1, $2)` 138 | 139 | `$1` Output 140 | 141 | `$2` Expected 142 | 143 | Assert that a given integer is less than or equal to an expected integer. 144 | 145 | * `skip()` 146 | 147 | Skip the current test case. 148 | 149 | ## License 150 | 151 | `bashunit` is licenced under a 152 | [BSD License](https://github.com/djui/bashunit/blob/master/LICENSE). 153 | -------------------------------------------------------------------------------- /bashunit.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ######################################################################## 4 | # GLOBALS 5 | ######################################################################## 6 | 7 | verbose=2 8 | caller=$0 9 | lineshow=0 10 | eol="\n" 11 | 12 | bashunit_passed=0 13 | bashunit_failed=0 14 | bashunit_skipped=0 15 | 16 | ######################################################################## 17 | # ASSERT FUNCTIONS 18 | ######################################################################## 19 | 20 | # Assert that a given expression evaluates to true. 21 | # 22 | # $1: Expression 23 | assert() { 24 | if test $* ; then _passed ; else _failed "$*" true ; fi 25 | } 26 | 27 | # Assert that a given output string is equal to an expected string. 28 | # 29 | # $1: Output 30 | # $2: Expected 31 | assertEqual() { 32 | echo $1 | grep -E "^$2$" > /dev/null 33 | if [ $? -eq 0 ] ; then _passed ; else _failed "$1" "$2" ; fi 34 | } 35 | 36 | # Assert that a given output string is not equal to an expected string. 37 | # 38 | # $1: Output 39 | # $2: Expected 40 | assertNotEqual() { 41 | echo $1 | grep -E "^$2$" > /dev/null 42 | if [ $? -ne 0 ] ; then _passed ; else _failed "$1" "$2" ; fi 43 | } 44 | 45 | # Assert that a given output string starts with an expected string. 46 | # 47 | # $1: Output 48 | # $2: Expected 49 | assertStartsWith() { 50 | echo $1 | grep -E "^$2" > /dev/null 51 | if [ $? -eq 0 ] ; then _passed ; else _failed "$1" "$2" ; fi 52 | } 53 | 54 | # Assert that the last command's return code is equal to an expected integer. 55 | # 56 | # $1: Output 57 | # $2: Expected 58 | # $?: Provided 59 | assertReturn() { 60 | local code=$? 61 | if [ $code -eq $2 ] ; then _passed ; else _failed "$code" "$2" ; fi 62 | } 63 | 64 | # Assert that the last command's return code is not equal to an expected integer. 65 | # 66 | # $1: Output 67 | # $2: Expected 68 | # $?: Provided 69 | assertNotReturn() { 70 | local code=$? 71 | if [ $code -ne $2 ] ; then _passed ; else _failed "$code" "$2" ; fi 72 | } 73 | 74 | # Assert that a given integer is greater than an expected integer. 75 | # 76 | # $1: Output 77 | # $2: Expected 78 | assertGreaterThan() { 79 | if [ $1 -gt $2 ] ; then _passed ; else _failed "$1" "$2" ; fi 80 | } 81 | 82 | # Assert that a given integer is greater than or equal to an expected integer. 83 | # 84 | # $1: Output 85 | # $2: Expected 86 | assertAtLeast() { 87 | if [ $1 -ge $2 ] ; then _passed ; else _failed "$1" "$2" ; fi 88 | } 89 | 90 | # Assert that a given integer is less than an expected integer. 91 | # 92 | # $1: Output 93 | # $2: Expected 94 | assertLessThan() { 95 | if [ $1 -lt $2 ] ; then _passed ; else _failed "$1" "$2" ; fi 96 | } 97 | 98 | # Assert that a given integer is less than or equal to an expected integer. 99 | # 100 | # $1: Output 101 | # $2: Expected 102 | assertAtMost() { 103 | if [ $1 -le $2 ] ; then _passed ; else _failed "$1" "$2" ; fi 104 | } 105 | 106 | # Skip the current test case. 107 | # 108 | skip() { 109 | _skipped 110 | } 111 | 112 | _failed() { 113 | bashunit_failed=$((bashunit_failed+1)) 114 | 115 | local ts=${BASH_SOURCE[2]} 116 | local tc=${FUNCNAME[2]} 117 | local line=${BASH_LINENO[1]} 118 | local my_source="eval sed -n -e \"$line p\" ${BASH_SOURCE[2]}" 119 | if [ $verbose -ge 2 ] ; then 120 | if [ $lineshow -eq 1 ]; then 121 | failed_line=":$($my_source)" 122 | else 123 | failed_line= 124 | fi 125 | echo -e "\033K[$ts:\033[37;1m$tc\033[0m:$line:\033[31mFailed\033[0m${failed_line}" 126 | fi 127 | if [ $verbose -eq 3 ] ; then 128 | echo -e "\033[31mExpected\033[0m: $(sed '2,$ s/^/ /g' <<<$2)" 129 | echo -e "\033[31mProvided\033[0m: $(sed '2,$ s/^/ /g' <<<$1)" 130 | fi 131 | } 132 | 133 | _passed() { 134 | bashunit_passed=$((bashunit_passed+1)) 135 | 136 | local ts=${BASH_SOURCE[2]} 137 | local tc=${FUNCNAME[2]} 138 | local line=${BASH_LINENO[1]} 139 | if [ $verbose -ge 2 ] ; then 140 | printf "\033[K$ts:\033[37;1m$tc\033[0m:$line:\033[32mPassed\033[0m$eol" 141 | fi 142 | } 143 | 144 | _skipped() { 145 | bashunit_skipped=$((bashunit_skipped+1)) 146 | 147 | local ts=${BASH_SOURCE[2]} 148 | local tc=${FUNCNAME[2]} 149 | local line=${BASH_LINENO[1]} 150 | local my_source="eval sed -n -e \"$line s/skip //; $line p\" ${BASH_SOURCE[2]}" 151 | if [ $verbose -ge 2 ] ; then 152 | if [ $lineshow -eq 1 ]; then 153 | skipped_line=":$($my_source)" 154 | else 155 | skipped_line= 156 | fi 157 | printf "\033[K$ts:\033[37;1m$tc\033[0m:$line:\033[33mSkipped\033[0m${skipped_line}$eol" 158 | fi 159 | } 160 | 161 | ######################################################################## 162 | # RUN 163 | ######################################################################## 164 | 165 | usage() { 166 | echo "Usage: [options...]" 167 | echo 168 | echo "Options:" 169 | echo " -v, --verbose Print expected and provided values" 170 | echo " -s, --summary Only print summary omitting individual test results" 171 | echo " -q, --quiet Do not print anything to standard output" 172 | echo " -l, --lineshow Show failing or skipped line after line number" 173 | echo " -f, --failed Print only individual failed test results" 174 | echo " -h, --help Show usage screen" 175 | } 176 | 177 | runTests() { 178 | local test_pattern="test[a-zA-Z0-9_]\+" 179 | local testcases=$(declare -F | \ 180 | sed -ne '/'"$test_pattern"'$/ { s/declare -f // ; p }') 181 | 182 | if [ ! "${testcases[*]}" ] ; then 183 | usage 184 | exit 0 185 | fi 186 | 187 | for tc in $testcases ; do $tc ; done 188 | 189 | if [ $verbose -gt 1 ] ; then 190 | printf "\033[K" 191 | fi 192 | if [ $verbose -ge 1 ] ; then 193 | echo "Done. $bashunit_passed passed." \ 194 | "$bashunit_failed failed." \ 195 | "$bashunit_skipped skipped." 196 | fi 197 | exit $bashunit_failed 198 | } 199 | 200 | # Arguments 201 | while [ $# -gt 0 ]; do 202 | arg=$1; shift 203 | case $arg in 204 | "-v"|"--verbose") verbose=3;; 205 | "-s"|"--summary") verbose=1;; 206 | "-q"|"--quiet") verbose=0;; 207 | "-l"|"--lineshow") lineshow=1;; 208 | "-f"|"--failed") eol="\r";; 209 | "-h"|"--help") usage; exit 0;; 210 | *) shift;; 211 | esac 212 | done 213 | 214 | runTests 215 | -------------------------------------------------------------------------------- /test_example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | testEcho() { 4 | assertEqual "$(echo foo)" "foo" 5 | assertReturn "$(echo foo)" 0 6 | } 7 | 8 | testTest() { 9 | assert "-e $0" 10 | } 11 | 12 | testArithmetic() { 13 | assertGreaterThan "$(( 1 + 1 ))" "1" 14 | assertAtLeast "$(( 1 + 1 ))" "2" 15 | assertLessThan "$(( 1 + 1 ))" "5" 16 | assertAtMost "$(( 1 + 1 ))" "2" 17 | } 18 | 19 | source $(dirname $0)/bashunit.bash 20 | --------------------------------------------------------------------------------