before(:each) for all tests except one

2020-08-12 16:00发布

This is part of my spec_helper.rb:

RSpec.configure do |config|

 config.before(:each) do
  login(email, password)
  visit root_url
 end

end

that I need in all of my (20+) tests except one.

Is there a way to avoid that single test to execute the before hook?

5条回答
叼着烟拽天下
2楼-- · 2020-08-12 16:28

You can add metadata to tests that do not need to login, then evaluate that metadata in your before hook.

For example, two tests in the same file. One needs to login and one does not.

# foo_spec.rb
describe Foo do
  describe "#bar" do
    it "needs to log in" do
      expect(1).to eq 1
    end
  end
  describe "#baz" do
    it "needs to not log in", :logged_out do
      expect(1).to eq 1
    end
  end
end

So we added metadata to our it block. Next, we configure the before hook to evaluate the example's metadata.

config.before(:each) do |test|
  login(email, password) unless test.metadata[:logged_out]
  visit root_url
end

Now, each test will visit root_url but only the ones not tagged with :logged_out will call login.

RSpec calls these metadata based hooks filters. You can learn a bit more about them here.

查看更多
看我几分像从前
3楼-- · 2020-08-12 16:31

Another option is to continue using the configuration in spec_helper.rb and when the test starts in the spec where I don't need it, do

describe "test" do
 it "1" do
  logout
  visit(another_page)
  .
  .
  .
 end
end
查看更多
小情绪 Triste *
4楼-- · 2020-08-12 16:34

Putting this kind of code into spec helper seems a bit odd. Feature specs is all you have? No unit tests? Even if it's the former, copy that code into individual specs that need it. If they're all in the same file, you can use contexts to prevent some duplication.

RSpec.describe 'something' do
  context 'specs with login' do
    before do 
      login(email, password)
      visit root_url
    end

    it { ... }
  end

  context 'specs without login' do
    it { ... }
  end
end

Global rspec config in spec_helper.rb is meant for other things. Ones that make sense for each and every spec. Like, for example, cleaning a database.

config.before :each do 
  DatabaseCleaner.clean
end
查看更多
▲ chillily
5楼-- · 2020-08-12 16:37

You can also do the check inside spec_helper's config.before(:each) block based on the test.metadata[:described_class] or [:example_group].

It has tons of information about the current context so it might be a bit more straightforward to do the filtering from inside the block instead of changing the specs individually.

查看更多
倾城 Initia
6楼-- · 2020-08-12 16:45

Whether it's 1 or 10 which don't need it, sadly it doesn't change the fact that any code in spec_helper.rb is going to apply to all. Another option from the answer above is to create a spec_login.rb file with that before hook code, then require it within the test files which need it.

spec/spec_login.rb

RSpec.configure do |config|

 config.before(:each) do
  login(email, password)
  visit root_url
 end

end

spec/1_spec.rb (needs login)

require 'spec_login'

describe 'BlahBlah' do

end

spec/2_spec.rb (no login)

describe 'BlahBlah' do

end
查看更多
登录 后发表回答