Rspec refactoring?

I have the following test with two almost identical blocks. Now I am looking for ways to reorganize this cleanly.

Test:

context "with the d1 configuration" do before (:each) do # send a message @envelope = Factory(:envelope, :destination => '32495xxxxxx', :message => 'Message sent by d1') @distributor = Distributor.find_by_name(Distributor::D1) @result = @envelope.send_to(@distributor) end it "should created a new sms-message" do @envelope.sent_messages.size.should == 1 end it "should have created one sms-message linked to the envelope and distributor" do sms = @envelope.sent_messages.find_by_distributor_id(@distributor.id) sms.should be_instance_of(SentMessage) sms.external_message_id.should_not == nil sms.sent_message_status_id.should == SentMessageStatus::IN_PROGRESS end it "should add a logline for the creation of the sms-message" do @envelope.log_lines.size.should == 2 @envelope.log_lines.last.message.should =~ /^Sent message/ end end context "with the correct d2 configuration" do before (:each) do # send a message @envelope = Factory(:envelope, :destination => '32495xxxxxx', :message => 'Message sent by d2') @distributor = Distributor.find_by_name(Distributor::D2) @result = @envelope.send_to(@distributor) end it "should created a new sms-message" do @envelope.sent_messages.size.should == 1 end it "should have created one sms-message linked to the envelope and distributor" do sms = @envelope.sent_messages.find_by_distributor_id(@distributor.id) sms.should be_instance_of(SentMessage) sms.external_message_id.should_not == nil sms.sent_message_status_id.should == SentMessageStatus::IN_PROGRESS end it "should add a logline for the creation of the sms-message" do @envelope.log_lines.size.should == 2 @envelope.log_lines.last.message.should =~ /^Sent message/ end end 

As you can say, there are two identical code blocks, each for a different distributor, D1 and D2 (they have more meaningful names in our project :)), and now I need to add a third distributor. How can I do it?

I can iterate over an array containing the changing parts (in this case: distributor name and message content). But can I change the name of the test?

What are the best approaches here? Is it possible to create some kind of test template where you can fill in certain values โ€‹โ€‹and execute them?

+3
source share
2 answers

Yes, you can skip the array / hash full of examples, and yes, you can rename contexts based on this, but you will need to know about the problems associated with defining the scope, for example, context is a class-level scope, but the test is an instance . Therefore, you must configure these things in the instance variables in the "Configuration" section of the context. I basically did this with a unit: test + shoulda (not rspec), so I might have messed up the scope rules a bit, but they should be similar

Note. I have not tested the code below, so it may be the victim of such problems ...

 # name this better than I have CONFIGS = {'d1' => {:name => Distributor::D1 :destination => '32495xxxxxx', :message => 'd1 message'}, 'd2' => {:name => Distributor::D2 :destination => '98765xxxxxx', :message => 'd2 message'} } # etc CONFIGS.each do |display_name, dist_hash| context "with the #{display_name} configuration" do before (:each) do # scope the value-hash here to make it available to test-cases # (you don't have to if you're just using it in the setup section) @dist_hash = dist_hash # send a message @envelope = Factory(:envelope, :destination => @dist_hash[:destination], :message => @dist_hash[:message]) @distributor = Distributor.find_by_name(@dist_hash[:name]) @result = @envelope.send_to(@distributor) end it "should created a new sms-message" do @envelope.sent_messages.size.should == 1 end it "should have created one sms-message linked to the envelope and distributor" do sms = @envelope.sent_messages.find_by_distributor_id(@distributor.id) sms.should be_instance_of(SentMessage) sms.external_message_id.should_not == nil sms.sent_message_status_id.should == SentMessageStatus::IN_PROGRESS end it "should add a logline for the creation of the sms-message" do @envelope.log_lines.size.should == 2 @envelope.log_lines.last.message.should =~ /^Sent message/ end end end 
+2
source

I had a pair programming session with a more experienced colleague, and together we came to the next solution.

First, we defined some common behavior:

 subject {@envelope} let(:the_sent_message){ @envelope.sent_messages.find_by_distributor_id(@distributor.id)} shared_examples_for "a typical sent envelope" do it{should have(1).sent_messages } it{should have(2).log_lines } end shared_examples_for "a successful delivery" do it("should have 1 IN_PROGRESS sms-message") { the_sent_message.should be_in_progress } it "should have 1 sms-message with external ref" do the_sent_message.external_message_id.should_not == nil end it "should log the delivery success" do @envelope.log_lines.last.message.should =~ /^Sent message/ end end shared_examples_for "a failing delivery" do it("should have 1 FAILED sms-message") { the_sent_message.should be_failed } it "should have 1 sms-message and no external ref" do the_sent_message.external_message_id.should == nil end it "should log the delivery failure" do @envelope.log_lines.last.message.should =~ /^Failed to send/ end end 

and then the tests will become more readable!

 context "delivered by d1" do before do @distributor = Distributor.find_by_name(Distributor::D1) send_a_test_envelope_to(@distributor) end it_should_behave_like "a typical sent envelope" it_should_behave_like "a successful delivery" end context "delivered by d2" do before do @distributor = Distributor.find_by_name(Distributor::D2) send_a_test_envelope_to(@distributor) end it_should_behave_like "a typical sent envelope" it_should_behave_like "a successful delivery" end 

and we also extracted the following method

 def send_a_test_envelope_to(distributor) @envelope = Factory(:envelope, :destination => '32495xxxxxx', :message => "Message sent by #{@distributor.name}") @envelope.send_to(distributor) end 

Now I can apply the suggested answer @Taryn, but I'm not quite sure that I really need it more.

+4
source

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


All Articles