Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Before block in rspec is running before every test when it should run only once

I am running a before do at the beginning of my tests. I would like this before to be executed once before running my tests. However at the moment it is running before each test :

context "worker has failed first time and has generated only part of licenses" do
      before do
        order.already_went_through_license_worker = true
        order.save!
        order.pre_calculate_licenses
        partial_generate_from_bundles(order.expected_license_bundles)
        LicenseService.new.create_from_order(order.id)
      end
      let!(:licenses){ License.where(order_id: order.id)}
      specify { subject.count.should == 34 }
      specify { subject.pluck(:is_from_offer_special).count(true).should == 4}
      specify { subject.pluck(:is_from_offer_special).count(false).should == 30 }
      specify { subject.pluck("license_offer.offer_original_id").compact.map(&:values).flatten.count(offer.id).should == 30}
      specify { subject.pluck("license_offer_special.offer_special_original_id").compact.map(&:values).flatten.count(offer_special_cyclic.id).should == 3}
      specify { subject.pluck("license_offer_special.offer_special_original_id").compact.map(&:values).flatten.count(offer_special_non_cyclic.id).should == 1 }
    end

When I change it to before(:all) I get an error :

 let declaration `order` accessed in a `before(:context)` hook at:

How can I make the before block run only once.

like image 369
David Geismar Avatar asked Oct 17 '25 10:10

David Geismar


2 Answers

How can I make the before block run only once.

before(:all), you already did that.

When I change it to before(:all) I get an error:

That's a different, completely unrelated error. Your block does run only once, which is what you asked. The problem here is that a context-level block is trying to access example-level declarations. Kinda like trying to access instance variables from class methods: those variables don't exist yet!

One possible approach is to inline all dependencies (don't use let, put code directly into the block):

before :all do
  order = create :order # or whatever
  order.already_went_through_license_worker = true
  order.save!
  ...
end
like image 76
Sergio Tulentsev Avatar answered Oct 19 '25 00:10

Sergio Tulentsev


You can use one specify block approach if nothing else helps:

specify do 
 subject.count.should == 34
 subject.pluck(:is_from_offer_special).count(true).should == 4
 #...
end

But this has one drawback: if one expectation fails, the ones after it will not run. But you can fix that if you aggregate failures

specify aggregate_failures: true do 
 subject.count.should == 34
 subject.pluck(:is_from_offer_special).count(true).should == 4
 #...
end
like image 39
Grzegorz Avatar answered Oct 18 '25 22:10

Grzegorz