1

I'm using the apartment gem to manage a multi-tenant Rails app.

Side Note: If you're unfamiliar with the gem, switching apartments is simply switching the schema used on the Postgres DB back-end. You change apartment tenants with Apartment::Tenant.switch!(apartment)

I have several tests that test behavior under the context of a certain apartment tenant. To do that, I use the below setup (example shown for Controller specs)

RSpec.describe MyController, type: :controller do
  before(:each) do
    # Some global before() setup
  end

  context "foo apartment" do

    ### Option 1 - Using the around() hook
    around(:each) do |example|
      begin
        Apartment::Tenant.switch!("foo")
        example.run
      ensure
        Apartment::Tenant.switch!("public")
      end
    end

    ### Option 2 - Independent before() + after() hooks
    before(:each) { Apartment::Tenant.switch!("foo") }
    after(:each) { Apartment::Tenant.switch!("public") }


    it "tests that the foo apartment is being used" do
      expect(Apartment::Tenant.current).to eq("foo")
    end
  end
end

As you can see, there are two approaches to setting up the test. One uses the around() hook and the other does the same thing, but independently uses the before() and after() hooks.

I'd imagine that both approaches are equivalent and interchangeable. But surprisingly only Option 2 actually works.

Is there a reason for this behavior? Does the around() block run in some different order than the before() block?

user2490003
  • 10,706
  • 17
  • 79
  • 155
  • 1
    Based on the [docs](https://www.relishapp.com/rspec/rspec-core/v/3-4/docs/hooks/around-hooks), `around` accomplishes a similar goal as `before` and `after`. But "`around` hooks do not share state with the example the way `before` and `after` hooks do." Check out the docs; there are a bunch of examples in there as well. – orde Jan 27 '16 at 20:16
  • I think that answers it, I missed it when I read through the docs. Thanks! If you want to move your comment to an answer I'd be happy to mark it as answered. – user2490003 Jan 27 '16 at 21:21
  • 1
    Also note that your #some global before() setup block will actually get run inside the around block -- which is most likely the cause here, since I'm assuming that global setup block resets the Tenant – Thomas Walpole Jan 27 '16 at 21:38

1 Answers1

3

An around(:each) block will wrap all before(:each) blocks (even those defined at an outer scope level). Because of this with your option 1 around block you're getting the following behavior

around_before
  global before() setup block
  example runs
around_after

If your global setup block sets a default tenant or anything it would be overwriting what you're doing in your around block

with option 2 you get

global before() setup block
before block
example runs
after block
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78