Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change the order of before hooks in rspec

I have a controller spec like this :

describe "#create" do
  before { post 'create', params }
  context "when the artist is valid" do
    before { allow(artist).to receive(:save).and_return(true) }
    it { expect(page).to redirect_to(root_path) }
    it { expect(notifier).to have_received(:notify) }
  end
end

This is a simple spec but It doesn't work because the describe's before block is executed before the context's before block. So, the result of artist.save is not stubed when the create action is called.

It tried to do this :

describe "first describe" do
  before { puts 2 }
  describe "second describe" do
    before { puts 1 }
    it "simple spec" do
      expect(1).to eq 1
    end
  end
end

I see the "2" before the "1". I'm not sure but I think it was working with previous versions.

I know, I can do this :

describe "#create" do
  context "when the artist is valid" do
    before { allow(artist).to receive(:save).and_return(true) }
    it "redirect to the root path" do
      post 'create', params
      expect(page).to redirect_to(root_path)
    end

    it "do notifications" do
      post :create, params
      expect(notifier).to have_received(:notify)
    end
  end
end

But I think it's less clean.

I found, on this page, http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/Hooks#before-instance_method than the order should be this :

before(:suite) # declared in RSpec.configure
before(:all)   # declared in RSpec.configure
before(:all)   # declared in a parent group
before(:all)   # declared in the current group
before(:each)  # declared in RSpec.configure
before(:each)  # declared in a parent group
before(:each)  # declared in the current group

It's not the case on this example.

I'm not sure but I think it was working with older versions of rspec.

Is there a solution?

like image 920
Dougui Avatar asked Jul 22 '13 00:07

Dougui


1 Answers

I would strongly recommend against you changing the order of hooks in rspec. That will make your app non-standard and Rails is build on standards and having things work as expected.

Everything you're describing it "as designed". Outer before blocks are always called before inner blocks.

Your example that you feel is "less clean" is the standard way to do controller specs. I actually encourage you to do it this way so that it is more maintainable/readable. It does not look unclean to me at all.

That said, there are some options:

  1. You can use a method. I have more than once had a method that was do_post or something similar
  2. You can use a let block which is initialized lazily. I would find it unlcean if it relied on other before blocks running first, but it's an option.
  3. You can define subject. https://www.relishapp.com/rspec/rspec-core/v/2-6/docs/subject/explicit-subject
like image 173
John Hinnegan Avatar answered Sep 28 '22 05:09

John Hinnegan