In rspec / capybara integration tests, how can N (sequential) steps be implemented as examples of N 'it ... do'?

For the messaging application, we have fairly lengthy integration tests. Right now, to execute a specific scenario, you need to perform approximately 20 or 30 steps in a specific sequence, because step N responds to the data created in step N-1.

So, they are currently organized under one example of "it ... do":

describe WidgetController do describe "long opt-in opt-out scenario" do it "can complete the full sequence" do # 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 # the one opt-out does not get the message # the four opt-ins get the message # verify the format of the message 

Each step has one or two statements to make sure that the step has done the right thing. So, currently we have 40+ statements in one example of it...do , which completely hides what is actually being tested.

We could insert the puts statement at each step to output the description, but it would be better if our N steps could be processed as examples of N rspec.

Is there a way to organize N steps of sequential integration, like N separate examples of it...do , therefore (a) they are executed sequentially, and (b) the state is maintained between the steps and (c) (ideally) allows us to continue using a random sowing order other tests that we run?

+4
source share
1 answer

I would separate testing from preparing a test to make it cleaner. This means that 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 can put this in before(:all) and then do 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 check the before(:all) steps in separate tests:

 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 little code duplication, but this makes the tests simple and readable, and so I would go for it.

Finally, to organize your tests, use shared_context . Therefore, if you need to prepare the same things in different tests / files, include them as 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 just use include_context 'big message broadcast' so that it is prepared wherever you like.

0
source

Source: https://habr.com/ru/post/1438274/


All Articles