5

What is the conventional way to set a variable once to be used by all examples in an RSpec suite?

I currently set a global variable in spec_helper that checks whether the specs are being run in a "debug mode"

$debug = ENV.key?('DEBUG') && (ENV['DEBUG'].casecmp('false') != 0) && (ENV['DEBUG'].casecmp('no') != 0)

How do I make this information available to all the examples in the suite without using a global variable and without re-computing the value for each context and/or example? (My understanding is that using a before(:all) block would re-compute it once per context; but, that before(:suite) can't be used to set instance variables.)

(Note: I'm asking more to learn about good design that to address this specific problem. I know one global isn't a big deal.)

2 Answers 2

8

for this purpose I usually write custom modules that I can include in the spec_helper.rb file.

Let's say that I am testing a back-end API and I don't want to parse every time the JSON response body.

spec/
spec/spec_helper.rb
spec/support/request_helper.rb
spec/controllers/api/v1/users_controller_spec.rb

I first define a function in a module placed under the support subfolder.

# request_helper.rb
module Request
  module JsonHelpers
    def json_response
      @json_response ||= JSON.parse(response.body, symbolize_names: true)
    end
  end
end

Then I include this module by default for some test types

#spec_helper.rb
#...
RSpec.configure do |config|
  config.include Request::JsonHelpers, type: :controller
end

Then I use methods defined in the test.

# users_controller_spec.rb
require 'rails_helper'

RSpec.describe Api::V1::UsersController, type: :controller do
  # ...

 describe "POST #create" do

    context "when is successfully created" do
      before(:each) do
        @user_attributes = FactoryGirl.attributes_for :user
        post :create, params: { user: @user_attributes }
      end

      it "renders the json representation for the user record just created" do
        user_response = json_response[:user]
        expect(user_response[:email]).to eq(@user_attributes[:email])
      end

      it { should respond_with 201 }
    end
end

In your case, you could create a module such as

module EnvHelper
  def is_debug_mode?
    @debug_mode ||= ENV['DEBUG']
  end
end

Then you can include it and simply use the method is_debug_mode? in your tests.

Sign up to request clarification or add additional context in comments.

1 Comment

Really nice, all worked except I had to manually require the helper in spec_helper. require_relative 'support/request_helper'
1

There is an easy way to keep all the setup stuff in spec_helper.rb, including custom variables, and access those variables in tests. The following is modified from the RSpec-core 3.10 docs, and is not Rails-specific.

Create a new setting for RSpec.configure called my_variable, and give it a value, like this:

# spec/spec_helper.rb

RSpec.configure do |config|
  config.add_setting :my_variable
  config.my_variable = "Value of my_variable"
end

Access settings as a new read-only property in RSpec.configuration from your test:

# spec/my_spec.rb

RSpec.describe(MyModule) do
  it "creates an instance of something" do
    my_instance = MyModule::MyClass.new(RSpec.configuration.my_variable)
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.