RSpec में DRY सिद्धांत का अनुप्रयोग



DRY (अपने आप को दोहराएं नहीं) आधुनिक विकास के कोने-कोने में से एक है, और विशेष रूप से रूबी प्रोग्रामर के बीच। लेकिन अगर, नियमित कोड लिखते समय, दोहराए जाने वाले अंशों को आमतौर पर तरीकों या अलग-अलग मॉड्यूल में आसानी से वर्गीकृत किया जा सकता है, तो परीक्षण लिखते समय, जहां कोड को दोहराना कभी-कभी और भी अधिक होता है, यह हमेशा आसान नहीं होता है। यह आलेख RSpec BDD ढांचे का उपयोग करते समय ऐसी समस्याओं के समाधान का एक छोटा सा अवलोकन प्रदान करता है।

1. साझा उदाहरण


Rspec के लिए पुन: प्रयोज्य कोड बनाने के लिए सबसे प्रसिद्ध और आमतौर पर इस्तेमाल की जाने वाली विधि। परीक्षण श्रेणी विरासत और मॉड्यूल समावेशन के लिए महान।

shared_examples "coolable" do let(:target){described_class.new} it "should make cool" do target.make_cool target.should be_cool end end describe User do it_should_behave_like "coolable" end 

इसके अलावा, साझा उदाहरण समूहों में कुछ अतिरिक्त कार्यक्षमता होती है, जो उन्हें उपयोग में बहुत अधिक लचीला बनाती है: मापदंडों को पार करना, ब्लॉक पास करना, और माता-पिता समूह में विधियों को परिभाषित करने के लिए उपयोग करना।

 shared_examples "coolable" do |target_name| it "should make #{ target_name } cool" do target.make_cool target.should be_cool end end describe User do it_should_behave_like "coolable", "target user" do let(:target){User.new} end end 

कहां और कैसे कुछ तरीके उपलब्ध होंगे, इसकी अधिक जानकारी के लिए डेविड चेलिमस्की [2] पढ़ें।

2. साझा संबंध


यह विशेषता इसकी सापेक्ष नवीनता (RSpec 2.6 में दिखाई गई) और एक संकीर्ण दायरे के कारण कुछ हद तक अज्ञात है। साझा संदर्भों का उपयोग करने के लिए सबसे उपयुक्त स्थिति कई चश्मे की उपस्थिति है जो समान प्रारंभिक मूल्यों या अंतिम क्रियाओं की आवश्यकता होती है, आमतौर पर पहले और बाद के ब्लॉकों में निर्दिष्ट होती हैं। इस पर प्रलेखन संकेत देता है:

 shared_context "shared stuff", :a => :b do before { @some_var = :some_value } def shared_method "it works" end let(:shared_let) { {'arbitrary' => 'object'} } subject do 'this is the subject' end end 

Share_context में एक बहुत ही सुविधाजनक चीज है, वर्णन ब्लॉक में निर्दिष्ट मेटा-जानकारी के अनुसार उन्हें शामिल करने की क्षमता:

 shared_context "shared with somevar", :need_values => 'some_var' do before { @some_var = :some_value } end describe "need som_var", :need_values => 'some_var' do it “should have som_var” do @some_var.should_not be_nil end end 


3. कारखाने की सुविधाएं


एक और सरल लेकिन बहुत महत्वपूर्ण बिंदु।

 @user = User.create( :email => 'example@example.com', :login => 'login1', :password => 'password', :status => 1, … ) 

ऐसे निर्माणों को बार-बार लिखने के बजाय, आपको factory_girl रत्न या इसके एनालॉग्स का उपयोग करना चाहिए। लाभ स्पष्ट हैं: कोड की मात्रा कम हो जाती है और यदि आप स्थिति को स्टेटस में बदलने का निर्णय लेते हैं तो सभी स्पेक्स को फिर से लिखने की आवश्यकता नहीं है।

4. खुद के मैचर्स


अपने स्वयं के गेमर्स को परिभाषित करने की क्षमता RSpec में सबसे अच्छी विशेषताओं में से एक है, धन्यवाद जिससे आप अपने चश्मे की पठनीयता और शान बढ़ा सकते हैं। तुरंत एक उदाहरण।
करने के लिए:
 it “should make user cool” do make_cool(user) user.coolness.should > 100 user.rating.should > 10 user.cool_things.count.should == 1 end 

के बाद:
 RSpec::Matchers.define :be_cool do match do |actual| actual.coolness.should > 100 && actual.rating.should > 10 && actual.cool_things.count.should == 1 end end it “should make user cool” do make_cool(user) user.should be_cool end 

सहमत हूं, यह बहुत बेहतर हो गया है।
RSpec आपको अपने स्वयं के मिलानकर्ताओं के लिए त्रुटि संदेश सेट करने, विवरण प्रदर्शित करने और जंजीर प्रदर्शन करने की अनुमति देता है, जो मिलानकर्ताओं को इतना लचीला बना देता है कि वे केवल अंतर्निहित लोगों से भिन्न नहीं होते हैं। उनकी पूरी शक्ति का एहसास करने के लिए, मैं निम्नलिखित उदाहरण का प्रस्ताव करता हूं [1]:

 RSpec::Matchers.define :have_errors_on do |attribute| chain :with_message do |message| @message = message end match do |model| model.valid? @has_errors = model.errors.key?(attribute) if @message @has_errors && model.errors[attribute].include?(@message) else @has_errors end end failure_message_for_should do |model| if @message "Validation errors #{model.errors[attribute].inspect} should include #{@message.inspect}" else "#{model.class} should have errors on attribute #{attribute.inspect}" end end failure_message_for_should_not do |model| "#{model.class} should not have an error on attribute #{attribute.inspect}" end end 


5. सिंगल लाइन


RSpec सरल चश्मा लिखने के लिए सिंगल-लाइन सिंटैक्स का उपयोग करने की क्षमता प्रदान करता है।

एक वास्तविक ओपनसोर्स परियोजना ( कामिनी ) से एक उदाहरण:
 context 'page 1' do subject { User.page 1 } it { should be_a Mongoid::Criteria } its(:current_page) { should == 1 } its(:limit_value) { should == 25 } its(:total_pages) { should == 2 } it { should skip(0) } end end 

स्पष्ट रूप से बहुत बेहतर:
 context 'page 1' do before :each do @page = User.page 1 end it “should be a Mongoid criteria” do @page.should be_a Mongoid::Criteria end it “should have current page set to 1do @page.current_page.should == 1 end …. #etc 


6. गतिशील रूप से बनाए गए चश्मा


यहां मुख्य बिंदु यह है कि यह निर्माण (साथ ही संदर्भ और वर्णन) केवल एक विधि है जो अंतिम तर्क के रूप में कोड का एक ब्लॉक लेता है। इसलिए, उन्हें साइकिल, और परिस्थितियों में बुलाया जा सकता है, और यहां तक ​​कि ऐसी संरचनाएं भी बना सकते हैं:

 it(it("should process +"){(2+3).should == 5}) do (3-2).should == 1 end 

वैसे तो दोनों ही स्पेक्स सफल हैं, लेकिन यह सोचने में भी डरावना है कि यह एक ही छोरों और पुनरावृत्तियों के विपरीत कहां लागू किया जा सकता है। उसी कामिनी से एक उदाहरण:

 [User, Admin, GemDefinedModel].each do |model_class| context "for #{model_class}" do describe '#page' do context 'page 1' do subject { model_class.page 1 } it_should_behave_like 'the first page' endend end end 

या शर्तों के साथ एक उदाहरण:

 if Mongoid::VERSION =~ /^3/ its(:selector) { should == {'salary' => 1} } else its(:selector) { should == {:salary => 1} } end 


7. मैक्रोज़


2010 में, साझा उदाहरणों की नई कार्यक्षमता की शुरुआत के बाद, डेविड चेलिमस्की ने कहा कि मैक्रों की अब आवश्यकता नहीं है। हालांकि, अगर आपको अभी भी लगता है कि यह आपके चश्मे के कोड को बेहतर बनाने का सबसे उपयुक्त तरीका है, तो आप उन्हें कुछ इस तरह से बना सकते हैं:

 module SumMacro def it_should_process_sum(s1, s2, result) it "should process sum of #{s1} and #{s2}" do (s1+s2).should == result end end end describe "sum" do extend SumMacro it_should_process_sum 2, 3, 5 end 

मैं इस बिंदु को अधिक विस्तार से नहीं देखता, लेकिन यदि आप चाहें, तो आप [4] पढ़ सकते हैं।

8. आज्ञा और विषय


ऐनक को निष्पादित करने से पहले प्रारंभिक मानों को आरंभ करने के लिए लेट और सब्जेक्ट का निर्माण आवश्यक है। बेशक, हर कोई पहले से ही जानता है कि इस तरह से हर कल्पना में लिखना:
 it “should do something” do user = User.new … end 

सभी महानों में नहीं, लेकिन आमतौर पर हर कोई इस कोड को पहले भेज देता है:

 before :each do @user = user.new end 

हालाँकि आपको विषय का उपयोग करना चाहिए। और यदि इससे पहले कि विषय विशेष रूप से "नामहीन" था, तो अब इसका उपयोग स्पष्ट रूप से चर के नाम को निर्दिष्ट करके भी किया जा सकता है:

 describe "number" do subject(:number){ 5 } it "should eql 5" do number.should == 5 end end 


आज्ञा देना विषय के समान है, लेकिन विधियों को घोषित करने के लिए उपयोग किया जाता है।

संबंधित लिंक


1. कस्टम RSpec-2 माचिस
solnic.eu/2011/01/14/custom-rspec-2-matchers.html
2. डेविड चेलिमस्की - RSpec-2 में साझा उदाहरण समूहों के साथ मिश्रण को निर्दिष्ट करना
blog.davidchelimsky.net/2010/11/07/specifying-mixins-with-shared-example-groups-in-rspec-2
3. बेन शेहिरमैन - विषय और लेट्स ब्लॉक के साथ अपनी Rspec फाइलें सुखाएं
benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks
4. बेन माबे - RSpec में मैक्रोज़ लिखना
benmabey.com/2008/06/08/writing-macros-in-rspec.html

और निष्कर्ष में, मैं केवल कह सकता हूं, मैं केवल यह कह सकता हूं - कम दोहराने की कोशिश करो।

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


All Articles