Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set variable once for all examples in RSpec suite (without using a global variable)

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.)

like image 204
Zack Avatar asked Mar 08 '23 02:03

Zack


2 Answers

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.

like image 149
mabe02 Avatar answered Apr 26 '23 05:04

mabe02


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
like image 27
Mike Slinn Avatar answered Apr 26 '23 05:04

Mike Slinn