Test-driving a rails script/runner script

April 15th, 2008 by rickbradley 1 comment »

We’re committed to being truly test-driven. That means writing a test for EVERYTHING before the code is written. That means you don’t have a Rails migration without writing a test first that fails until that migration is written and applied. That means when you write rake tasks you write tests for them. That means when you write scripts to do data loading, for example – a real example that came up over the past few days – you write tests before you write the scripts.

I messed around with rspec, script/runner, dug through optparse.rb, played for a while and finally found a simple recipe for testing script/runner scripts in Rails apps (among other scripts in other places).

Here’s a set of rspec examples:

  
require File.dirname(__FILE__) + '/../../spec_helper'
require 'claim_parser/claims_importer'

describe "running the import_claims.rb script via script/runner" do
  def run_script
    eval File.read(File.join(RAILS_ROOT, 'lib', 'claim_parser', 'import_claims.rb'))
  end

  describe 'when no filename is specified on the command-line' do
    before :each do
      Object.send(:remove_const, :ARGV)
      ARGV = []
    end

    it 'should fail' do
      lambda { run_script }.should raise_error(ArgumentError)
    end
  end

  describe 'when a filename is specified on the command-line' do
    before :each do
      @filename = '/path/to/some/fictional/claims/file'
      Object.send(:remove_const, :ARGV)
      ARGV = [ @filename ]
      @importer = stub('claims importer', :run => true)
      ClaimsImporter.stubs(:new).returns(@importer)
    end

    it 'should create a ClaimsImporter instance' do
      ClaimsImporter.expects(:new).returns(@importer)
      run_script      
    end

    it 'should provide the command-line specified filename when creating the ClaimsImporter' do
      ClaimsImporter.expects(:new).with(@filename).returns(@importer)
      run_script
    end    

    it 'should call the run method on the ClaimsImporter instance' do
      @importer.expects(:run)
      run_script
    end
  end
end

And the corresponding script:

  
#
# Import claims data
#
#   (run with script/runner)
#

require 'claim_parser/claims_importer'

raise ArgumentError, "A claims data filename is required" if ARGV.blank? or ARGV[0].blank?

ClaimsImporter.new(ARGV[0]).run

1 Response to “Test-driving a rails script/runner script”

  1. Yossef Says:

    I told you before I liked that eval File.read trick. I’m going to have to use it in flac2mp3 to get rid of those pending specs.

Leave a Reply