Skip to content

Instantly share code, notes, and snippets.

@erik-megarad
Created November 11, 2014 18:55
Show Gist options
  • Save erik-megarad/5df43818f1058f380631 to your computer and use it in GitHub Desktop.
Save erik-megarad/5df43818f1058f380631 to your computer and use it in GitHub Desktop.
describe "A long-running process" do
before(:context) do # Have to use before(:context) instead of subject() to make the long-running task only execute once
@input_one = 1
@input_two = 2 # Can't use let() in before(:context)
@my_test_object = MyTestClass.new
@my_test_object.thing_that_takes_thirty_minutes(@input_one, @input_two)
end
# Multiple assertions
it 'calculates the output correctly' do
@my_test_object.value.should eq 3
end
it 'does not set the failed flag' do
@my_test_object.failed.should be_nil
end
end
@myronmarston
Copy link

Here's a little extension that provides something very similar to what you're asking for:

module RSpecContextMemoization
  def let(name, &block)
    attr_reader name
    before(:context) { instance_variable_set(:"@#{name}", block.call) }
  end
end

RSpec.configure do |config|
  config.extend RSpecContextMemoization, memoization_scope: :context
end

Put that in spec/spec_helper.rb (or somewhere that is always loaded) and then tag example groups in which you want let/subject memoization to have context rather than example scope with memoization_scope: :context. Your example would become:

describe "A long-running process", memoization_scope: :context do
  let(:input_one) { 1 }
  let(:input_two) { 2 }
  let(:my_test_object) { MyTestClass.new }

  subject(:thing_that_takes_thirty_minutes) do
    my_test_object.thing_that_takes_thirty_minutes(input_one, input_two)
  end

  it 'calculates the output correctly' do
    expect { thing_that_takes_thirty_minutes }.to change {
      my_test_object.value
    }.to(3)
  end

  it 'does not set the failed flag' do
    expect { thing_that_takes_thirty_minutes }.to_not change {
      my_test_object.failed
    }
  end
end

...and it should just work.

It's trivial to add this functionality on top of what RSpec already provides. We field enough questions where users get confused when misusing before(:context) hooks that I don't want to add more features to RSpec that would encourage their (mis)use, particularly because it's so easy to add this kind of thing on top of the APIs already provided. It could make a great extension gem, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment