olliesaunders / bash_spec
- Source
- Commits
- Network (0)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Branch:
master
| name | age | message | |
|---|---|---|---|
| |
README | ||
| |
bash_spec | ||
| |
bash_spec.sh |
README
Thanks for downloading bash_spec and welcome to the world of behaviour driven bash!
===== Installation
Change directory to the one where this file is contained
and run these three commands:
$ ./configure
$ make
$ make install
===== Requirements
This library has been tested and written in bash 2.05b.0 on Darwin (Mac OS X).
It should work on any POSIX system.
It definitely won't work with sh or any non-BASH shells.
It might work for versions of BASH as low as 2.0 but definitely won't work for versions earlier than that.
===== Usage and Walkthrough
Once installed you can use bash spec in two ways. Either write specs inline (in the same file as the script itself) or
put your specs in a separate file. Inline specs are generally simpler but you might prefer to keep your functional code
and spec code separate.
Now I'll walk through the creation of a very basic script that tells you whether a number is odd or even.
It'll work like this:
$ odd_or_even 1
odd
$ odd_or_even 2
even
=== Inline Specs
First let's create a new file with the name we want to give our script:
$ touch odd_or_even
and make it executable:
$ chmod+x odd_or_even
Now let's it, I use TextMate personally.
$ mate odd_or_even
We'll put some standard things in the script, the shebang line and a comment saying what the script does:
#!/usr/bin/env bash
# odd_or_even, tells you whether a number is odd or even
Next we need to add a bit of logic to separate our spec code from functional code:
if [ "$(basename $0)" = 'bash_spec' ]; then
# specs go here
else
odd_or_even "$@"
fi
This basically says when this file is executed with the "bash_spec" command, run the specs. Otherwise
we'll call a function. By convention this function has the same name as the script itself, I recommend following this
convention. "$@" is a special bash variable that represents all arguments passed to the script. By using it we're
forwarding them all onto this function.
Given that we're calling this function it's probably a good idea to define it! You'll need to stick the
definition ABOVE the logic we just wrote.
odd_or_even () {
echo function body will go here
}
Now lets write some specs. Behaviour driven development is all about writing the spec BEFORE the functional code.
Here's my first spec:
should 'echo even when passed an even number'
@ "$(odd_or_even 2)" = 'even'
@ "$(odd_or_even 4)" = 'even'
Good bash practice is to quote appropriately if you don't understand why I'm using so many quotes you might want
to read up a bit more on bash itself.
The @ symbol works in the same way as the test command. So everything you can do with test you can do with @.
As such it is important to leave a space between @ and it's arguments. Check out the man page for test for all the
things you can do with it.
The condition itself is calling our function with a sub-shell so as to capture the output and allow it to be tested.
OK back to the shell. If we execute our script we should see that our function is called
$ ./odd_or_even
function body will go here
And if we run it with the bash_spec command the specs will be executed:
$ bash_spec odd_or_even
odd_or_even
should echo even when passed an even number
#1: [ function body will go here = even ] expected truth
#2: [ function body will go here = even ] expected truth
0 passes, 2 failures. 0 seconds
Here bash_spec is telling us that the spec we wrote are failing. This is to be expected because we haven't
written the actual code yet! It's good to run the spec anyway just to prove that it is indeed failing as it should.
Let's accelerate a bit here. I'm going to complete the specs with another should statement:
should 'echo odd when passed an odd number'
@ "$(odd_or_even 1)" = 'odd'
@ "$(odd_or_even 3)" = 'odd'
and then write the function body:
if [ $(($1 % 2)) -eq 1 ]; then
echo odd
else
echo even
fi
and run the spec again:
$ bash_spec odd_or_even
odd_or_even
4 passes, 0 failures. 0 seconds
Huzzah! This time bash_spec is telling us we have success! And we should be able to run the script and see
it behave as expected:
$ ./odd_or_even 1
odd
$ ./odd_or_even 2
even
And here's the final code:
#!/usr/bin/env bash
# odd_or_even, tells you whether a number is odd or even
odd_or_even () {
if [ $(($1 % 2)) -eq 1 ]; then
echo odd
else
echo even
fi
}
if [ "$(basename $0)" = 'bash_spec' ]; then
should 'echo even when passed an even number'
@ "$(odd_or_even 2)" = 'even'
@ "$(odd_or_even 4)" = 'even'
should 'echo odd when passed an odd number'
@ "$(odd_or_even 1)" = 'odd'
@ "$(odd_or_even 3)" = 'odd'
else
odd_or_even "$@"
fi
Now I'm to change this code. Instead of outputting a word telling us whether the number is odd or even I'm
going to get it to return a success code indicating the same.
First I'm going to change the names of everything to reflect the new behaviour. I'm going to call it is_even.
A quick rename:
$ mv odd_or_even is_even
And edit:
$ mate is_even
I'll do a find and replace so that the contents of the file is changed as well. And I'm going to change
the descriptive comment at the top:
# is_even, exits 0 if number is even and 1 otherwise
At this point I'm going to run the specs again, just to make sure I haven't disrupted anything by using the find
and replace.
OK that worked, great.
Now let's change the specs.
should 'exit 0 when passed an even number'
is_even 2
@ $? -eq 0
is_even 4
@ $? -eq 0
should 'exit 1 when passed an odd number'
is_even 1
@ $? -eq 1
is_even 3
@ $? -eq 1
As you can see we don't have to use @ on every line, only lines where something has to be verified. In this case were
verifying the exit code of the previous command ($?).
If I run the spec for this it should fail. Here's the output I got:
is_even
even
even
odd
should echo odd when passed an odd number
#1: [ 0 -eq 1 ] expected truth
odd
#2: [ 0 -eq 1 ] expected truth
2 passes, 2 failures. 0 seconds
Obviously it's not working because the functional code needs to be changed. So I'm going to update that to this:
is_even () {
[ $(($1 % 2)) -eq 0 ]
}
And give that a whirl
=== Separate File Specs ===
Method 1 requires some additional logic so that the inline specs aren't executed when the script is run normally.
Method 2 requires you to source your script
