Test Driven Development

RSpec

Redirecting Spec's html Output to Browser

Use spec -fh to have Spec output its test results in nicely formatted html. Example:

spec -fh spec/models/person_spec.rb

Of course, html output on the prompt isn't really all that nice, so let's redirect the html to a browser:

spec -fh spec/models/person_spec.rb | firefox

Hm, results in a 'broken pipe'… Php to the rescue! This forum post gives us a php script which turns Spec's output into a temporary file. The script subsequently opens firefox with this file and you're presented with a great Spec report.

I have crudely adjusted the code for my own needs:

#!/usr/bin/php-cgi
<?PHP

$fp = fopen('php://stdin','r+');

$n = 1;
while(!feof($fp)){
// read our line in from STDIN
$line.= trim(fgets($fp,4096));
flush();
++$n;
}
fclose($fp);


if (($argc <= 3) && (!in_array('help', $argv))) {

$file_tmp = 'Pipe2Browser-'.substr(md5(date("U")),14,19).
(((strlen($argv[1]) < 5) && (strlen($argv[1]) > 0)) ? $argv[1] : '.html' );

if (file_exists('/tmp/pipe2browser'))
if (!is_dir('/tmp/pipe2browser')) {
exec('rm /tmp/pipe2browser');
} else { // remove this "else" condition if you don't want temps to autoclean...
exec('ls /tmp/pipe2browser', $lsres);
if ($lsres) exec('rm -r /tmp/pipe2browser/*');
}

if (!file_exists('/tmp/pipe2browser'))
exec('mkdir /tmp/pipe2browser');

$file_tmp = '/tmp/pipe2browser/'.$file_tmp;

exec('echo "'.addslashes($line).'" > '.$file_tmp);

//$browser = '/Applications/Safari.app';
$browser = 'firefox -new-window';
if ($argc == 2) {
if (is_file($argv[1]) || (is_dir($argv[1]) && strpos($argv[1], '.app'))) $browser = $argv[1];
}
if ($argc == 3) {
if (is_file($argv[2]) || (is_dir($argv[2]) && strpos($argv[2], '.app'))) $browser = $argv[2];
}

//exec('open -a '.$browser." '".$file_tmp."'");
exec($browser." '".$file_tmp."'");
} else {
echo 'Error! Usage: $ pipe2browser [file_extension] [/Applications/YourBrowser.app]';
exit(1);
}

echo "\n";

exit(0);
?>

As the forum post says, do a sudo chmod +x pipe2browser to get the script going (and do not forget to place it into your .scripts directory where it will be found automatically). As an aside: this script could of course easily be rewritten in Ruby (but I'm just to lazy to do that myself).

There's also a Perl oneliner (from a blog post) which does very much the same thing:

#!/usr/bin/perl -00
use File::Temp;$f=File::Temp->new;print{$f}<>;system qw{firefox -remote},"openURL(file://$f, new-tab)"

Except that the temp file is no longer available if you use the -new-window option (instead of -remote) for firefox…

Issues When Performing Multiple Tests

In my experience, RSpec caches each class it encounters when running multiple tests. So, if you do something like:

script/spec spec/models/*_spec.rb

And these are your tests:

a_spec.rb
b_spec.rb
c_spec.rb

Then all classes loaded in a_spec.rb will not be reloaded for the tests in b_spec and c_spec. While this is undoubtedly great for performance, it sometimes causes trouble.

Observe this code:

describe Asset do
  
  fixtures :asset_types, :organizations, :users, :assets, :allotments, :facilities

  before(:each) do
    class Asset
      default_scope nil
    end    
    @asset = Asset.new
  end
  ...
end

This overwrites a default_scope setting in class Asset (because it causes trouble in RSpec when used in combination with Globalize2-specific default_scopes). If however, class Asset was loaded by another RSpec test (in the same test run), then you're in trouble!

Solution: put the overwrite in the very first test, as well as in the original test.


Personal Tools