Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

टेस्ट-कमिट-रिवर्ट: लिगेसी रूबी कोड को सुरक्षित रूप से टेस्ट करने के लिए एक व्यावहारिक वर्कफ़्लो

यह हम सभी के साथ होता है। जैसे-जैसे सॉफ़्टवेयर प्रोजेक्ट बढ़ते हैं, कोडबेस के कुछ हिस्से एक व्यापक टेस्ट सूट के बिना प्रोडक्शन में चले जाते हैं। जब आप कुछ महीनों बाद कोड के उसी क्षेत्र को फिर से देखते हैं, तो इसे समझना मुश्किल हो सकता है; इससे भी बदतर, इसमें एक बग हो सकता है, और हमें नहीं पता कि इसे ठीक करना कहां से शुरू करें।

टेस्ट के बिना कोड को संशोधित करना एक बड़ी चुनौती है। हम निश्चित नहीं हो सकते कि हम इस प्रक्रिया में कुछ तोड़ देंगे, और सब कुछ मैन्युअल रूप से जांचना, सबसे अच्छा, गलतियों की संभावना है; आमतौर पर, यह असंभव है।

इस तरह के कोड से निपटना डेवलपर्स के रूप में हमारे द्वारा किए जाने वाले सबसे आम कार्यों में से एक है, और कई तकनीकों ने वर्षों से इस मुद्दे पर ध्यान केंद्रित किया है, जैसे कि कैरेक्टराइज़ेशन टेस्ट, जिन पर हमने पिछले लेख में चर्चा की थी।

आज, हम कैरेक्टराइज़ेशन टेस्ट पर आधारित एक और तकनीक को कवर करेंगे और जिसे केंट बेक द्वारा पेश किया गया था, जिन्होंने कई साल पहले आधुनिक प्रोग्रामिंग दुनिया में TDD को भी पेश किया था।

TCR क्या है?

TCR का अर्थ है "टेस्ट, कमिट, रिवर्ट", लेकिन इसे "टेस्ट && कमिट || रिवर्ट" कहना अधिक सटीक है। आइए देखें क्यों।

यह तकनीक लिगेसी कोड को टेस्ट करने के लिए एक वर्कफ़्लो का वर्णन करती है। हम एक स्क्रिप्ट का उपयोग करेंगे जो हर बार जब हम अपनी प्रोजेक्ट फाइलों को सेव करते हैं तो टेस्ट चलाती है। प्रक्रिया इस प्रकार है:

  • सबसे पहले, हम लिगेसी कोड के उस हिस्से के लिए एक खाली यूनिट टेस्ट बनाते हैं जिसे हम टेस्ट करना चाहते हैं।
  • फिर हम एक सिंगल एसर्टेशन जोड़ते हैं और टेस्ट को सेव करते हैं।
  • चूंकि हमने अपनी स्क्रिप्ट सेट कर ली है, टेस्ट स्वचालित रूप से चलता है। यदि यह सफल होता है, तो परिवर्तन कमिट हो जाता है। यदि यह विफल होता है, तो परिवर्तन हटा दिया जाता है (रिवर्ट), और हमें फिर से प्रयास करने की आवश्यकता होती है।

एक बार टेस्ट पास हो जाने पर, हम एक नया टेस्ट केस जोड़ सकते हैं।

अनिवार्य रूप से, TCR आपके कोड को "ग्रीन" स्थिति में रखने के बारे में है, बजाय पहले एक फेलिंग टेस्ट लिखने (रेड) और फिर इसे पास कराने (ग्रीन) के, जैसा कि हम टेस्ट-ड्रिवन डेवलपमेंट के साथ करते हैं। यदि हम एक फेलिंग टेस्ट लिखते हैं, तो यह बस गायब हो जाएगा, और हमें फिर से "ग्रीन" स्थिति में वापस लाया जाएगा।

उद्देश्य

इस तकनीक का मुख्य लक्ष्य हर बार टेस्ट केस जोड़ने पर कोड को थोड़ा बेहतर समझना है। यह स्वाभाविक रूप से टेस्ट कवरेज बढ़ाएगा और कई रीफैक्टरिंग को अनब्लॉक करेगा जो अन्यथा संभव नहीं होते।

TCR के फायदों में से एक यह है कि यह कई परिदृश्यों में उपयोगी है। हम इसे बिना किसी टेस्ट वाले कोड के साथ या आंशिक रूप से टेस्ट किए गए कोड के साथ उपयोग कर सकते हैं। यदि टेस्ट पास नहीं होता है, तो हम बस परिवर्तन को रिवर्ट करते हैं और फिर से प्रयास करते हैं।

हम इसका उपयोग कैसे कर सकते हैं?

केंट बेक विभिन्न लेखों और वीडियो में (अंत में लिंक किए गए) दिखाते हैं कि एक अच्छा दृष्टिकोण एक स्क्रिप्ट का उपयोग करना है जो प्रोजेक्ट में कुछ फाइलों के सेव होने के बाद चलती है।

यह आपके द्वारा टेस्ट करने का प्रयास कर रहे प्रोजेक्ट पर बहुत अधिक निर्भर करेगा। निम्नलिखित जैसी स्क्रिप्ट, जो एडिटर में एक प्लगइन का उपयोग करके हर बार फाइलों को सेव करने पर निष्पादित होती है, एक अच्छी शुरुआत है:

(rspec && git commit -am "WIP") || git reset --hard 

यदि आप विजुअल स्टूडियो कोड का उपयोग कर रहे हैं, तो हर सेव पर निष्पादित करने के लिए एक अच्छा प्लगइन "runonsave" है। आप उपरोक्त कमांड या अपने प्रोजेक्ट के लिए एक समान कमांड शामिल कर सकते हैं। इस मामले में, संपूर्ण कॉन्फ़िग फाइल होगी:

{ 
  "folders": [{ "path": "." }], 
  "settings": { 
    "emeraldwalk.runonsave": { 
      "commands": [ 
        { 
          "match": "*.rb", 
          "cmd": "cd ${workspaceRoot} && rspec && git commit -am WIP || git reset --hard" 
        } 
      ] 
    } 
  } 
} 

याद रखें कि बाद में, आप कमिट को गिट के साथ सीधे कमांड लाइन में या PR मर्ज करते समय स्क्वैश कर सकते हैं यदि आप गिटहब का उपयोग कर रहे हैं:

टेस्ट-कमिट-रिवर्ट: लिगेसी रूबी कोड को सुरक्षित रूप से टेस्ट करने के लिए एक व्यावहारिक वर्कफ़्लो

इसका मतलब है कि हमें मुख्य ब्रांच में केवल एक कमिट मिलेगा, उस ब्रांच पर हमारे द्वारा किए गए सभी कमिट्स के लिए जिस पर हम काम कर रहे हैं। गिटहब का यह आरेख इसे अच्छी तरह से समझाता है:

टेस्ट-कमिट-रिवर्ट: लिगेसी रूबी कोड को सुरक्षित रूप से टेस्ट करने के लिए एक व्यावहारिक वर्कफ़्लो

TCR के साथ हमारा पहला टेस्ट लिखना

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

हम बस एक परिवर्तन कर सकते हैं और परिवर्तनों को डेप्लॉय कर सकते हैं। हालांकि, हम यह सुनिश्चित करना चाहते हैं कि हम इस प्रक्रिया में कुछ भी न तोड़ें, जो हमेशा एक अच्छा विचार है।

# worker.rb 
class Worker 
  def initialize(age, active_years, veteran) 
    @age = age 
    @active_years = active_years 
    @veteran = veteran 
  end 
  
  def can_retire? 
    return true if @age >= 67 
    return true if @active_years >= 30 
    return true if @age >= 60 && @active_years >= 25 
    return true if @veteran && @active_years > 25 
    false 
  end 
end 

पहला कदम टेस्ट के लिए एक नई फाइल बनाना होगा, ताकि हम वहां उन्हें जोड़ना शुरू कर सकें। हमने can_retire? मेथड में पहली पंक्ति देखी है:

 def can_retire? 
   return true if @age >= 67 
   ... 
   ... 
 end 

इस प्रकार, हम पहले इस केस को टेस्ट कर सकते हैं:

# specs/worker_spec.rb 
require_relative './../worker' 
describe Worker do 
  describe 'can_retire?' do 
    it "should return true if age is higher than 67" do 
    end 
  end 
end 

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

यदि हम उपरोक्त फाइल को ऐसे ही सेव करते हैं, तो हम फिर टेस्ट के लिए एक लाइन जोड़ सकते हैं।

require_relative './../worker' 
describe Worker do 
  describe 'can_retire?' do 
    it "should return true if age is higher than 67" do 
      expect(Worker.new(70, 10, false).can_retire?).to be_true ## यह लाइन अब सेव करने पर गायब हो सकती है 
    end 
  end 
end 

जब हम सेव करते हैं, यदि नई लाइन गायब नहीं होती है, तो हमने अच्छा काम किया है; टेस्ट पास हो जाता है!

अधिक टेस्ट जोड़ना

एक बार हमारे पास पहला टेस्ट हो जाने पर, हम झूठे मामलों को ध्यान में रखते हुए अधिक केस जोड़ते रह सकते हैं। कुछ काम के बाद, हमारे पास ऐसा कुछ है:

# frozen_string_literal: true 
require_relative './../worker' 
describe Worker do 
  describe 'can_retire?' do 
    it 'should return true if age is higher than 67' do 
      expect(Worker.new(70, 10, false).can_retire?).to be true 
    end 
    it 'should return true if age is 67' do 
      expect(Worker.new(67, 10, false).can_retire?).to be true 
    end 
    it 'should return true if age is less than 67' do 
      expect(Worker.new(50, 10, false).can_retire?).to be false 
    end 
    it 'should return true if active years is higher than 30' do 
      expect(Worker.new(60, 31, false).can_retire?).to be true 
    end 
    it 'should return true if active years is 30' do 
      expect(Worker.new(60, 30, false).can_retire?).to be true 
    end 
  end 
end 

हर मामले में, हम पहले "इट" ब्लॉक लिखते हैं, सेव करते हैं, और फिर expect(...) के साथ एसर्टेशन जोड़ते हैं।

हमेशा की तरह, हम उतने टेस्ट जोड़ सकते हैं जितने संभव हों, लेकिन एक बार जब हम अपेक्षाकृत निश्चित हो जाते हैं कि सब कुछ कवर हो गया है, तो बहुत अधिक जोड़ने का कोई मतलब नहीं है।

अभी भी कुछ केस कवर करने बाकी हैं, इसलिए हमें पूर्णता के लिए उन्हें जोड़ना चाहिए।

अंतिम टेस्ट

यहां इसका अंतिम रूप में स्पेक फाइल है। जैसा कि आप देख सकते हैं, हम अभी भी अधिक केस जोड़ सकते हैं, लेकिन मुझे लगता है कि यह TCR की प्रक्रिया को स्पष्ट करने के लिए पर्याप्त है।

# frozen_string_literal: true 
require_relative './../worker' 
describe Worker do 
  describe 'can_retire?' do 
    it 'should return true if age is higher than 67' do 
      expect(Worker.new(70, 10, false).can_retire?).to be true 
    end 
    it 'should return true if age is 67' do 
      expect(Worker.new(67, 10, false).can_retire?).to be true 
    end 
    it 'should return true if age is less than 67' do 
      expect(Worker.new(50, 10, false).can_retire?).to be false 
    end 
    it 'should return true if active years is higher than 30' do 
      expect(Worker.new(60, 31, false).can_retire?).to be true 
    end 
    it 'should return true if active years is 30' do 
      expect(Worker.new(20, 30, false).can_retire?).to be true 
    end 
    it 'should return true if age is higher than 60 and active years is higher than 25' do 
      expect(Worker.new(60, 30, false).can_retire?).to be true 
    end 
    it 'should return true if age is higher than 60 and active years is higher than 25' do 
      expect(Worker.new(61, 30, false).can_retire?).to be true 
    end 
    it 'should return true if age is 60 and active years is higher than 25' do 
      expect(Worker.new(60, 30, false).can_retire?).to be true 
    end 
    it 'should return true if age is higher than 60 and active years is 25' do 
      expect(Worker.new(61, 25, false).can_retire?).to be true 
    end 
    it 'should return true if age is 60 and active years is 25' do 
      expect(Worker.new(60, 25, false).can_retire?).to be true 
    end 
    it 'should return true if is veteran and active years is higher than 25' do 
      expect(Worker.new(60, 25, false).can_retire?).to be true 
    end 
  end 
end 

रीफैक्टर करने के तरीके

अगर आप यहां तक पढ़े हैं, तो शायद कुछ ऐसा है जो कोड के साथ थोड़ा अजीब लगता है। हमारे पास कई "जादुई नंबर" हैं जिन्हें स्थिरांक में निकाला जाना चाहिए, टेस्ट और Worker क्लास दोनों में।

हम मुख्य can_retire? पब्लिक मेथड में प्रत्येक केस के लिए प्राइवेट मेथड भी बना सकते हैं।

मैं दोनों संभावित रीफैक्टरिंग को आपके लिए अभ्यास के रूप में छोड़ दूंगा। हालांकि, अब हमारे पास टेस्ट हैं, इसलिए अगर हम किसी भी चरण में गलती करते हैं, तो वे हमें बताएंगे।

निष्कर्ष

मैं आपको अपने प्रोजेक्ट्स के साथ TCR आज़माने के लिए प्रोत्साहित करता हूं। यह एक बहुत सस्ता प्रयोग है क्योंकि आपको किसी बाहरी सर्वर में फैंसी कंटीन्यूअस इंटीग्रेशन या नई लाइब्रेरी पर निर्भरता की आवश्यकता नहीं है। आपको बस अपने कंप्यूटर पर कुछ फाइलों को सेव करने पर कमांड निष्पादित करने का एक तरीका चाहिए।

यह टेस्ट जोड़ते समय एक "गेमिंग" अनुभव भी देगा, जो हमेशा मजेदार और दिलचस्प होता है। इसके अलावा, आपके एडिटर से फेलिंग टेस्ट को हटाने का अनुशासन आपको एक अतिरिक्त सुरक्षा जाल देगा, यह पुष्टि करके कि आप जो टेस्ट रिपॉजिटरी में पुश कर रहे हैं वे पास हो रहे हैं।

मुझे उम्मीद है कि आप लिगेसी कोड से निपटने में इस नई तकनीक को उपयोगी पाएंगे। मैंने पिछले कुछ महीनों में इसका कई बार उपयोग किया है, और यह हमेशा एक खुशी की बात रही है।

अतिरिक्त संसाधन

  • परिचय के रूप में अच्छा वीडियो।
  • VS कोड में TCR का उपयोग कैसे करें पर केंट बेक का दृष्टिकोण।
  • सेव पर स्क्रिप्ट चलाने के लिए VS कोड का प्लगइन।
  1. Ruby on Rails में महारत: इस सिद्ध फ्रेमवर्क के साथ शक्तिशाली वेब ऐप्स तेजी से बनाएं Ruby on Rails में महारत: इस सिद्ध फ्रेमवर्क के साथ शक्तिशाली वेब ऐप्स तेजी से बनाएं

    Ruby on Rails (कभी-कभी RoR) सबसे लोकप्रिय ओपन-सोर्स वेब एप्लिकेशन फ्रेमवर्क है। यह Ruby प्रोग्रामिंग भाषा के साथ बनाया गया है। आप सिंपल से लेकर कॉम्प्लेक्स तक एप्लिकेशन बनाने में मदद के लिए Rails का उपयोग कर सकते हैं, Rails के साथ आप जो हासिल कर सकते हैं उसकी कोई सीमा नहीं है! फ्रेमवर्क क्या है? फ्र

  1. Rack को समझना: Ruby वेब फ्रेमवर्क्स की रीढ़ Rack को समझना: Ruby वेब फ्रेमवर्क्स की रीढ़

    हर Rails, Sinatra, और अन्य Ruby वेब फ्रेमवर्क्स के पीछे क्या हो रहा है? उत्तर है Rack, वह प्रमुख घटक जो इसे संभव बनाता है। लेकिन Rack वास्तव में क्या है? Rack फ्रेमवर्क (Rails) और एप्लिकेशन सर्वर (Puma) के बीच एक परत है। यह वह गोंद है जो उन्हें संवाद करने की अनुमति देता है। हम Rack का उपयोग क्यों क

  1. रूबी में स्टैटिक एनालिसिस में महारत: पार्सर जेम के साथ मेथड्स और पैरामीटर्स निकालें रूबी में स्टैटिक एनालिसिस में महारत: पार्सर जेम के साथ मेथड्स और पैरामीटर्स निकालें

    मान लीजिए कि आप अपने सोर्स कोड को पार्स करके अपने सभी मेथड्स ढूंढना चाहते हैं, वे कहां परिभाषित हैं और वे कौन से तर्क लेते हैं। आप यह कैसे कर सकते हैं? आपका पहला विचार इसके लिए एक रेगेक्स लिखना हो सकता है… लेकिन क्या कोई बेहतर तरीका है? हाँ! स्टैटिक एनालिसिस एक तकनीक है जिसका उपयोग आप तब कर सकते है