capistrano-spec

Capistrano… the final frontier of testing… well, maybe not final, but it is
a frontier. I had set out to do some bug fixing and some BDDing on some of
my capistrano code, but found it wasn't really obvious how to do so. As
a result, I set out to write capistrano-spec and document how to test
capistrano libraries.

Install

You know the drill:

geminstallcapistrano-spec

And require it in your spec/spec_helper.rb:

require'capistrano-spec'

Designing your capistrano extension

In the wild, you'll mostly commonly come across two patterns:

files living under recipes/* that are autoloaded

files living under lib that are required from config/deploy.rb

In these files, you can start using the capistrano top-level methods, like
namespace or task, like:

Capistrano does some trickery to require and load
so that if you require or load, the file is ran
in the context of a Capistrano::Configuration, where all the
task and namespace methods you know and love will
be available.

Some consider this a little gross, because it'd be easy to accidentally
require/load this without being in the context of a
Capistrano::Configuration. The answer to this is to pull use
Capistrano::Configuration.instance to make sure it's
evaluted in that context:

There's a problem though: it's not particular testable. You
can't take some Capistrano::Configuration and easily bring
your task into it.

So, here's what I recommend instead: create a method for taking a
configuration, and adding your goodies to it.

require'capistrano'moduleCapistranomoduleSpeakdefself.load_into(configuration)configuration.loaddotask:speakdoset:message,'oh hai'putsmessageendendendendend# may as well load it if we have it
ifCapistrano::Configuration.instanceCapistrano::Speak.load_into(Capistrano::Configuration.instance)end

Now, we're going to be able to test this. Behold!

Testing

Alright, we can start testing by making Capistrano::Configuration and load
Capistrano::Speak into it.

describeCapistrano::Speak,"loaded into a configuration"dobeforedo@configuration=Capistrano::Configuration.newCapistrano::Speak.load_into(@configuration)endend

Now you have access to a configuration, so you can start poking around the
@configuration object as you see fit.

One thing you might be wondering now is… that's cool, but what about
working with remote servers? I have just the trick for you: extensions to
Capistrano::Configuration to track what files were up or downloaded and
what commands were run. Now, this is no substitution for manually testing
your capistrano recipe by running it on the server, but it is good for
sanity checking.