# Bats

Shell scripting is a great tool, but rarely is it tested. Enter BATS! In this post I will give a quick tutorial on how to use it to test scripts.

#!/usr/bin/env bats

@test "running a command" {
run foogrep "bar" foo_file
[ "$status" -eq 1 ] [ "$output" = "1: bar baz" ]
}


Shameless plug: Before we start, I recommend downloading the language grammar package - language-bats for the Atom editor.

If you have never used RSpec or other testing framework the idea is simple: your code is run against expectations and if those are met then the tests pass. The framework deals with the heavy lifting of executing the tests, printing the results, and providing to the correct interface to Continuous Integration servers.

BATS is a test runner for Bash scripts. Before each run BATS takes the file and splits each test into its own file. BATS then runs each test file to see if passes or fails. Anything you can do in Bash you can do in BATS, and if any command fails then the entire test fails.

## A Basic test

BATS syntax for a test is @test "desc" {}. But if you want it to run the file individually you should add the shebang line. The simplest test looks something like this:

#!/usr/bin/env bats

@test "something" {
false
}


This isn’t very useful, but it will generate a failing test.

### Skipping tests

Simetimes it is a useful to skip a test. Just add skip at the point you want to the test to be skipped. You can add a description or not.

@test "just skip" {
skip
}

@test "skip for a reason" {
[ "$output" == "foo" ] }  ### Hooks Sometimes multiple tests need to share the same state. In testing every test should stand on its own and leave no artifacts. To accomplish this we can use the setup and teardown hooks.  setup() { mkdir -p /tmp/output } teardown() { rm -rf /tmp/output } @test "writes files" { write_files_to "/tmp/output" run "ls /tmp/output" [ "$output" == "test-file" ]
}