A blog about software development and other software related matters

Blog Archive

Monday, June 23, 2008

Testing those black sheep

One of the common reasonings for not writing tests is that writing tests for some code types isn't always possible nor cost effective, iv nicked them as the BDD black sheep, lets take for example command line API's, such API's are rarely tested & for some good(?) reasons like:


  • Its so simple, why do we need to test it?

  • Its hard to access, how can we assert anything in such an environment?

  • I hate it! let me get over this and get back to the safety zone of my UI!


While these are all compelling (>.<) reasons they are only plain excuses, writing command line API's is very tricky, it requires many validations and care in order to function properly, as for the hating part id replace it with deep lovin the sooner the better, command line is the most efficient user API and is here to stay (like it or not).
There are some technical challenges when performing assertions and mimicking user input however they can be easily overcome with two techniques, the first is mocking and its great for mimicking user input, now i know what your thinking, is he bulshitting me or what? how can a simple mock type the damn keyboard!?
Well the simple answer is that it don't have to, lets think for a minute what do we actually need to test (its not stdin!), we don't need to test that the keyboard works and that the typed data was placed correctly into ARGV, we need test how this data is handled, which means that a mocked data structure has to be created when writing tests, the reason that im using a mock (and not a fixture) is that im assuming that your using some sort of an input parsing framework (your not re inventing the wheel are you??) such as optiflag (Ruby) or JOpt (Java) and that this parser has to be mocked in order to provide some nice input into our program entry point.
The second technique is stream redirecting (who?), well its not that complicated lets recap for a minute, the user types in data and gets feedback in the form of text which is spat onto the screen via (youv guessed it write) stdout, this means that in order to assert the functionality of our program all that we need to do is to assert what ever is printed out in different scenarios, this can be achieved by using stream redirection into some sort of buffer, in Ruby such an approach might look somthing like this:

def redirect
orig_defout = $stdout
$stdout = StringIO.new
yield
$stdout.string
ensure
$stdout = orig_defout
end

Which can be used like so:

it "should say hello if -f flag is set" do
ARGV.flags.should_receive(:h).and_return(true)
outputStr = redirect { @bash.process }
outputStr.should eql('Hello!')
end

Don't forget that if there are other wanted side effects (file changes, table updates, etc..) they should be asserted like in any other code that your testing.

No comments: