Assembly Line

Assembly Line allows you to group together a series of rspec let statements which can later be evaluated to set up a specific state for your specs. It's an excellent compliment to factory_girl because you can use your factories to build up each component, then use AssemblyLine to bring them all together.

As a system grows in complexity, more objects are required to set up the necessary state to write tests. Sometimes you'll need to write a test that requires access to the beginning, middle, and end of a very large hierarchy, and AssemblyLine can expose each part of the hierarchy that you care about.

Installation

gem install assembly_line

Edit your spec/spec_helper.rb

require 'assembly_line' # unnecessary if you've used config.gem 'assembly_line'
require 'spec/support/assemblies' # unnecessary if your spec_helper already requires spec/support/*

Spec::Runner.configure do |config|
  config.extend AssemblyLine
end

Define an AssemblyLine

AssemblyLine.define(:user_with_payment_address) do
  let(:user) { Factory(:user)}
  let(:payment_address) { Factory(:payment_address, :user => user) }
end

Example

Place your AssemblyLine definitions in spec/support/assemblies.rb

class Party < Struct.new(:host, :attendees)
  attr_writer :drinks
  def drinks
    @drinks ||= []
  end
end

AssemblyLine.define(:drinks) do
  let(:drinks) { [:gin, :vodka] }
end

AssemblyLine.define(:party) do
  depends_on :drinks

  let(:host) { :rochelle }
  let(:attendees) { [:nick, :ellis, :coach] }
  let(:party) { @party = Party.new(host, attendees) }
  let(:party_crasher) { attendees << :crasher; :crasher }
end

Use your AssemblyLine in a test

describe "README example" do
  context "attendees" do
    Assemble(:party)

    it "does not count the host as an attendee" do
      party.attendees.should_not include(host)
    end
  end

  context "party crasher" do
    Assemble(:party).invoke(:party_crasher)

    it "exemplifies method invocation after assembly" do
      party.attendees.should include(:crasher)
    end
  end

  context "drinks" do
    Assemble(:party)

    it "does not include the list of standard drinks" do
      party.drinks.should_not include(drinks)
    end
  end
end

Use your AssemblyLine in an irb session

AssemblyLine works a little differently when using it in irb. Your let definitions will not be defined globally (see e26a903), instead you'll have to prefix all defined methods with AssemblyLine.

>> Assemble(:drinks)
=> #<AssemblyLine::Constructor:0x10049e958 @code_block=#<Proc:0x000000010049ea98@(irb):1>, @name=:drinks, @rspec_context=AssemblyLine::GlobalContext, @options={}>
>>
>> AssemblyLine.drinks # the `drinks` method is prefixed with AssemblyLine
=> [:gin, :vodka]

Thanks!

  • l4rk (initial spike declaring modules and including them in the rspec context)
  • veezus (code contributions, introduced modular design / dependencies)
  • bigtiger (named the project)
  • leshill (support and testing, suggested irb support)
  • wgibbs (suggested irb support)

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright (c) 2010 Sandro Turriate. See MIT_LICENSE for details.