Rspec Around() Block Behaves Different from a Before() + After()
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...
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?
1 Answer
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