ऐसा हम में से अधिकांश के साथ होता है। जैसे-जैसे सॉफ्टवेयर प्रोजेक्ट बढ़ते हैं, कोडबेस के कुछ हिस्से बिना व्यापक परीक्षण सूट के उत्पादन में समाप्त हो जाते हैं। जब आप कुछ महीनों के बाद कोड के उसी क्षेत्र पर फिर से नज़र डालते हैं, तो इसे समझना मुश्किल हो सकता है; इससे भी बदतर, एक बग हो सकता है, और हम नहीं जानते कि इसे ठीक करना कहां से शुरू करें।
परीक्षण के बिना कोड को संशोधित करना एक बड़ी चुनौती है। हम सुनिश्चित नहीं हो सकते हैं कि क्या हम इस प्रक्रिया में कुछ भी तोड़ेंगे, और सब कुछ मैन्युअल रूप से जांचना, सबसे अच्छा, गलतियों से ग्रस्त है; आमतौर पर, यह असंभव है।
इस तरह के कोड से निपटना सबसे आम कार्यों में से एक है जिसे हम डेवलपर्स के रूप में करते हैं, और कई तकनीकों ने इस मुद्दे पर वर्षों से ध्यान केंद्रित किया है, जैसे कि लक्षण वर्णन परीक्षण, जिसकी चर्चा हमने पिछले लेख में की थी।
आज, हम कैरेक्टराइजेशन टेस्ट पर आधारित एक और तकनीक को कवर करेंगे और केंट बेक द्वारा पेश किया जाएगा, जिन्होंने कई साल पहले टीडीडी को आधुनिक प्रोग्रामिंग दुनिया में पेश किया था।
TCR क्या है?
TCR का मतलब "टेस्ट, कमिट, रिवर्ट" है, लेकिन इसे "टेस्ट &&कमिट || रिवर्ट" कहना अधिक सटीक है। आइए देखें क्यों।
यह तकनीक लीगेसी कोड का परीक्षण करने के लिए वर्कफ़्लो का वर्णन करती है। हम एक स्क्रिप्ट का उपयोग करेंगे जो हर बार जब हम अपनी प्रोजेक्ट फाइलों को सहेजेंगे तो परीक्षण चलाएंगे। प्रक्रिया इस प्रकार है:
- सबसे पहले, हम उस लीगेसी कोड के भाग के लिए एक खाली इकाई परीक्षण बनाते हैं जिसका हम परीक्षण करना चाहते हैं।
- फिर हम एक दावा जोड़ते हैं और परीक्षण सहेजते हैं।
- चूंकि हमने अपनी स्क्रिप्ट सेट अप कर ली है, इसलिए परीक्षण स्वचालित रूप से चलाया जाता है। यदि यह सफल होता है, तो परिवर्तन प्रतिबद्ध है। यदि यह विफल हो जाता है, तो परिवर्तन हटा दिया जाता है (वापस किया जाता है), और हमें फिर से प्रयास करने की आवश्यकता होती है।
एक बार परीक्षण पास हो जाने पर, हम एक नया परीक्षण केस जोड़ सकते हैं।
अनिवार्य रूप से, TCR आपके कोड को पहले (लाल) विफल परीक्षण लिखने के बजाय "हरे" स्थिति में रखने के बारे में है और फिर इसे पास (हरा) करता है, जैसा कि हम परीक्षण-संचालित विकास के साथ करते हैं। अगर हम एक असफल परीक्षण लिखते हैं, तो यह गायब हो जाएगा, और हमें फिर से "हरी" स्थिति में वापस लाया जाएगा।
उद्देश्य
इस तकनीक का मुख्य लक्ष्य हर बार टेस्ट केस जोड़ने पर कोड को थोड़ा बेहतर समझना है। यह स्वाभाविक रूप से परीक्षण कवरेज को बढ़ाएगा और कई रिफैक्टरिंग को अनब्लॉक करेगा, अन्यथा, संभव नहीं होगा।
TCR के फायदों में से एक यह है कि यह कई परिदृश्यों में उपयोगी है। हम इसका उपयोग उस कोड के साथ कर सकते हैं जिसका कोई परीक्षण नहीं है या कोड के साथ आंशिक रूप से परीक्षण किया गया है। यदि परीक्षण पास नहीं होता है, तो हम परिवर्तन को वापस कर देते हैं और पुनः प्रयास करते हैं।
हम इसका उपयोग कैसे कर सकते हैं?
केंट बेक विभिन्न लेखों और वीडियो (अंत में लिंक) में दिखाता है कि एक अच्छा तरीका एक स्क्रिप्ट का उपयोग कर रहा है जो प्रोजेक्ट में कुछ फाइलों के सहेजे जाने के बाद चलती है।
यह उस प्रोजेक्ट पर बहुत अधिक निर्भर करेगा जिसका आप परीक्षण करने का प्रयास कर रहे हैं। निम्न स्क्रिप्ट जैसा कुछ, जिसे हर बार जब हम संपादक में प्लग इन के साथ फ़ाइलें सहेजते हैं, निष्पादित किया जाता है, एक अच्छी शुरुआत है:
(rspec && git commit -am "WIP") || git reset --hard
यदि आप विजुअल स्टूडियो कोड का उपयोग कर रहे हैं, तो प्रत्येक सेव पर निष्पादित करने के लिए एक अच्छा प्लगइन "रनोनसेव" है। आप अपनी परियोजना के लिए उपरोक्त आदेश या इसी तरह के एक को शामिल कर सकते हैं। इस स्थिति में, संपूर्ण कॉन्फ़िग फ़ाइल होगी
{
"folders": [{ "path": "." }],
"settings": {
"emeraldwalk.runonsave": {
"commands": [
{
"match": "*.rb",
"cmd": "cd ${workspaceRoot} && rspec && git commit -am WIP || git reset --hard"
}
]
}
}
}
याद रखें कि बाद में, यदि आप Github का उपयोग कर रहे हैं, तो आप कमांड लाइन में या PR को मर्ज करते समय सीधे Git के साथ कमिट को स्क्वैश कर सकते हैं:
।
इसका मतलब है कि हम जिस शाखा पर काम कर रहे हैं, उस पर किए गए सभी कामों के लिए हमें मुख्य शाखा में केवल एक ही प्रतिबद्धता मिलेगी। Github का यह आरेख इसे अच्छी तरह से समझाता है:
.
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 ## This line can disappear when we save now
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
हर मामले में, हम पहले "it" ब्लॉक लिखते हैं, सेव करते हैं, और फिर 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
Refactor के तरीके
यदि आपने इसे अभी तक पढ़ा है, तो शायद कुछ ऐसा है जो कोड से थोड़ा हटकर है। हमारे पास कई "जादुई संख्याएं" हैं जिन्हें परीक्षण और कार्यकर्ता वर्ग दोनों में, स्थिरांक में निकाला जाना चाहिए।
हम मुख्य can_retir में प्रत्येक मामले के लिए निजी तरीके भी बना सकते हैं? सार्वजनिक विधि।
मैं आपके लिए अभ्यास के रूप में दोनों संभावित रिफैक्टरिंग छोड़ दूंगा। हालाँकि, हमारे पास अभी परीक्षण हैं, इसलिए यदि हम किसी भी चरण में कोई गलती करते हैं, तो वे हमें बताएंगे।
निष्कर्ष
मैं आपको अपनी परियोजनाओं के साथ TCR आज़माने के लिए प्रोत्साहित करता हूँ। यह एक बहुत ही सस्ता प्रयोग है क्योंकि आपको बाहरी सर्वर में किसी फैंसी निरंतर एकीकरण या नई लाइब्रेरी के साथ निर्भरता की आवश्यकता नहीं है। हर बार जब आप अपने कंप्यूटर पर कुछ फ़ाइलें सहेजते हैं तो आपको केवल एक कमांड निष्पादित करने की आवश्यकता होती है।
यह आपको परीक्षण जोड़ते समय एक "गेमिंग" अनुभव भी देगा, जो हमेशा मज़ेदार और दिलचस्प होता है। इसके अतिरिक्त, आपके संपादक से असफल परीक्षणों को हटाने का अनुशासन आपको यह पुष्टि करके एक अतिरिक्त सुरक्षा जाल प्रदान करेगा कि आप जिन परीक्षणों को रिपॉजिटरी में धकेल रहे हैं, वे पास हो रहे हैं।
मुझे आशा है कि लीगेसी कोड के साथ व्यवहार करते समय आपको यह नई तकनीक उपयोगी लगेगी। मैंने पिछले कुछ महीनों में कई बार उपयोग किया है, और यह हमेशा एक खुशी की बात रही है।
अतिरिक्त संसाधन
- परिचय के रूप में अच्छा वीडियो।
- वीएस कोड में टीसीआर का उपयोग करने के तरीके पर केंट बेक का विचार।
- सेव पर स्क्रिप्ट चलाने के लिए VS कोड का प्लगइन।