I'd separate the testing from preparing the test to make it cleaner. This means in your example for this one long test:
# create an account factory with trait account_type
# create manager factory for the account
# 5 people factories opt-in to that account
# 1 person then opts out
# a manager creates and sends a broadcast
--> no asserts until now, because that is test preparation
You could put this into before(:all)
and then make separate tests:
before(:all) do
# no asserts here, just the steps to do it
# create an account factory with trait account_type
# create manager factory for the account
# 5 people factories opt-in to that account
# 1 person then opts out
# a manager creates and sends a broadcast
# so in the end you got:
@people = ...
@manager = ...
@opt-ins = ...
@opt-out = ...
@broadcast = ...
end
it "should not send the message to the opt-out" do
# the one opt-out does not get the message
end
it "should send the message to the four opt-ins" do
# the four opt-ins get the message
end
it "should have the right message format" do
# verify the format of the message
end
In addition, you should also test the steps of the before(:all)
in separate tests, too:
it "should be able to create an account with account_type" do
# create an account factory with trait account_type
# assert it worked
end
it "should be able to create a manager for an account" do
# create an account factory with trait account_type
# no assertion that it worked (that is tested before)
# create manager factory for the account
# assert manager got correctly created
end
it "should be able to opt-in to accounts" do
# create an account factory with trait account_type
# no assertion that it worked (that is tested before)
# 5 people factories opt-in to that account
# assert that it worked
end
it "should be able to opt-in to accounts" do
# create an account factory with trait account_type
# 5 people factories opt-in to that account
# 1 person then opts out
# assert that it worked
end
There is a small code duplication, but that makes the tests simple and clearer to read and that's why I'd go for that.
Finally, to organize your tests, use a shared_context
. So if you need to prepare the same things in different tests/files, include them as a shared_context
:
# spec/contexts/big_message_broadcast.rb
shared_context "big message broadcast" do
before(:all) do
# no asserts here, just the steps to do it
# create an account factory with trait account_type
# create manager factory for the account
# 5 people factories opt-in to that account
# 1 person then opts out
# a manager creates and sends a broadcast
# so in the end you got:
@people = ...
@manager = ...
@opt-ins = ...
@opt-out = ...
@broadcast = ...
end
end
# spec/.../some_spec.rb
describe "long opt-in opt-out scenario" do
include_context 'big message broadcast'
it "should not send the message to the opt-out" do
...
end
...
end
That way you can simply use include_context 'big message broadcast'
to have it prepared wherever you like.