Skip to content

Writing tests

Tom edited this page Aug 12, 2019 · 3 revisions

There are a few rules you must follow when writing unit tests.

Each test function must start with Test

eg

# Treated like a unit test
function Test_A {
}
# Treated like a unit test
function TestABC {
}
# Not a unit test
function ABC {
}

This way you can write helper functions eg

# ignored by the tester
function createConnection {
 echo "Creating a network connection"
}

# ran by the tester
function Test_Connection {
  createConnection
  echo "Manipulating connection"
}

# ran by the tester
function Test_AnotherConnection {
 createConnection "A parameter"
 echo "Manipulating another connection"
}

As you can see above test don't need to have Assertions however that defeats the purpose of unit tests. So lets include some.

  • AssertEquals - 1: string, 2: string - Checks if both string are the same
  • AssertFileEquals - 1: file, 2: file - Compares 2 files to check if they are the same
  • AssertContains - 1:string, 2:string - checks if the second string is inside the first string
  • AssertFileContains - 1: file, 2: string - checks if the string is present in the file
  • AssertExists - 1: file/directory - checks if the file or directory exists
  • AssertTrue - 1: boolean statement - checks if the boolean statement evaluates to true (test fails if it is false)
  • Assert - 1: state, 2: message - asserts based on the state and uses the message as data. The state is either 1 or 0. 1=> error, 0 => Pass

When even one test fails the resulting exit code will be one. Useful for testing scripts in ci/cd pipelines

Lets see an example

# special function ran before every test
# it creates 2 empty files and a file containing abc def
function setupTest {
    touch empty1 empty2
    cat <<EOF > full
abc def
EOF
}

# special function ran after every test
# It removes all files from the filesystem
function destroyTest {
   rm empty1 empty2 full
}

# unit tests
function Test_AssertEquals {
        AssertEquals "abc" "abc" # Success
        AssertEquals "abc" "def" # Test failed abc doesn't equal def
}

# Test if files are equal
function Test_AssertFileEquals {
        AssertFileEquals "empty1" "empty2" # Success
        AssertFileEquals "empty1" "full" # Test failed both files are different
}

function Test_AssertContains {
        AssertContains "abcdef" "abc" # Success
        AssertContains "abcdef" "defg" # Test failed defg isn't in abcdef
}

function Test_AssertFileContains {
        AssertFileContains "full" "abc" # Success
        AssertFileContains "full" "ghi" # Test failed string isn't in the file
}

function Test_AssertExists {
          AssertExists "empty1" # empty1 exists (it is a file)
          AssertExists "." # . exists it is the current directory
          AssertExists "empty3" # fails. Empty3 isn't a file or directory
}

function Test_AssertTrue {
         AssertTrue [[ -f "empty1" ]] # evaluates to true so no problem
         AssertTrue [[ -f "empty3" ]] # evaluates to false so test fails
}

function Test_Assert {
         Assert "0" "No problem"
         Assert "1" "Error happened"
}

When running the above you should see something like this

 Running unit: test.shUnit
 special function ran before every test
 Running test: Test_AssertEquals
PASS: abc and abc are equal
ERROR: expected abc, but got def instead
 Running test: Test_AssertFileEquals
PASS: Files are equal
ERROR: File empty1 and File full are not equal
 Running test: Test_AssertContains
PASS: Substring abc found
ERROR: Substring defg not found in abcdef
 Running test: Test_AssertFileContains
PASS: Substring found in full
ERROR: Could not find ghi in full
 Running test: Test_AssertExists
PASS: empty1 exists
PASS: . exists
ERROR: empty3 is not a file/directory
 Running test: Test_AssertTrue
PASS: [[ -f empty1 ]] evaluated to true
ERROR: [[ -f empty3 ]] evaluated to false
 Running test: Test_Assert
PASS: No problem
ERROR: Error happened
--------------------------------------------------------
Pass: 8, Errors: 7

When even one test fails the resulting exit code will be one. Useful for testing scripts in ci/cd pipelines

Special functions

  • setup - runs once per file as first function
  • destroy - runs once per file as last function
  • setupTest - runs just before each test function
  • destroyTest - runs after each test function

In the examples above you see a use-case for setupTest and destroyTest

Clone this wiki locally