मुझे लगता है कि टीडीडी का उल्लेख है कि प्रश्न में कोड वास्तव में मौजूद नहीं है। यदि ऐसा होता है तो आप सही टीडीडी नहीं कर रहे हैं लेकिन टीएडी (टेस्ट-आफ डेवलपमेंट), जो स्वाभाविक रूप से इस तरह के प्रश्नों की ओर जाता है। टीडीडी में हम परीक्षण के साथ शुरू करते हैं। ऐसा प्रतीत होता है कि आप कुछ प्रकार के मेनू या कमांड सिस्टम का निर्माण कर रहे हैं, इसलिए मैं इसे एक उदाहरण के रूप में उपयोग करूंगा।
describe GameMenu do
it "Allows you to navigate to character creation" do
# Assuming character creation would require capturing additional
# information it violates SRP (Single Responsibility Principle)
# and belongs in a separate class so we'll mock it out.
character_creation = mock("character creation")
character_creation.should_receive(:execute)
# Using constructor injection to tell the code about the mock
menu = GameMenu.new(character_creation)
menu.execute("c")
end
end
यह परीक्षण कुछ निम्नलिखित (याद रखें, सिर्फ पर्याप्त कोड परीक्षण पारित करने के लिए, कोई और अधिक) के समान कोड
class GameMenu
def initialize(character_creation_command)
@character_creation_command = character_creation_command
end
def execute(command)
@character_creation_command.execute
end
end
के लिए नेतृत्व अब हम अगले परीक्षण जोड़ देंगे होगा।
class GameMenu
def initialize(character_creation_command, inventory_command)
@inventory_command = inventory_command
end
def execute(command)
if command == "i"
@inventory_command.execute
else
@character_creation_command.execute
end
end
end
इस कार्यान्वयन हमारे कोड के बारे में एक प्रश्न के लिए हमें ले जाता है:
it "Allows you to display character inventory" do
inventory_command = mock("inventory")
inventory_command.should_receive(:execute)
menu = GameMenu.new(nil, inventory_command)
menu.execute("i")
end
इस परीक्षण चल रहा है जैसे एक कार्यान्वयन करने के लिए हमें का नेतृत्व करेंगे। अमान्य आदेश दर्ज होने पर हमारा कोड क्या करना चाहिए? एक बार जब हम उस प्रश्न का उत्तर तय कर लेंगे तो हम एक और परीक्षण लागू कर सकते हैं।
it "Raises an error when an invalid command is entered" do
menu = GameMenu.new(nil, nil)
lambda { menu.execute("invalid command") }.should raise_error(ArgumentError)
end
कि अब बाहर ड्राइव execute
विधि
def execute(command)
unless ["c", "i"].include? command
raise ArgumentError("Invalid command '#{command}'")
end
if command == "i"
@inventory_command.execute
else
@character_creation_command.execute
end
end
के लिए एक त्वरित परिवर्तन है कि हम परीक्षण गुजर रहा है हम एक आशय में आदेश के सत्यापन को निकालने के लिए निकालें विधि रिफैक्टरिंग उपयोग कर सकते हैं विधि प्रकट करना।
def execute(command)
raise ArgumentError("Invalid command '#{command}'") if invalid? command
if command == "i"
@inventory_command.execute
else
@character_creation_command.execute
end
end
def invalid?(command)
!["c", "i"].include? command
end
अब हम अंततः उस बिंदु पर पहुंच गए हैं जहां हम आपके प्रश्न को संबोधित कर सकते हैं।चूंकि invalid?
विधि को परीक्षण के तहत मौजूदा कोड को पुन: सक्रिय करके संचालित किया गया था, इसके लिए यूनिट परीक्षण लिखने की कोई आवश्यकता नहीं है, यह पहले से ही कवर हो चुका है और यह स्वयं पर खड़ा नहीं है। चूंकि इन्वेंट्री और कैरेक्टर कमांड का परीक्षण हमारे मौजूदा परीक्षण द्वारा नहीं किया जाता है, इसलिए उन्हें स्वतंत्र रूप से परीक्षण करने की आवश्यकता होगी।
ध्यान दें कि हमारा कोड अभी भी बेहतर हो सकता है, जबकि परीक्षण पास हो रहे हैं, इसे थोड़ा और साफ़ करने दें। सशर्त बयान एक संकेतक है कि हम ओसीपी (ओपन-क्लोज़ेड सिद्धांत) का उल्लंघन कर रहे हैं हम सशर्त तर्क को हटाने के लिए पॉलीमोर्फिज्म रिफैक्टरिंग के साथ सशर्त प्रतिस्थापन का उपयोग कर सकते हैं।
# Refactored to comply to the OCP.
class GameMenu
def initialize(character_creation_command, inventory_command)
@commands = {
"c" => character_creation_command,
"i" => inventory_command
}
end
def execute(command)
raise ArgumentError("Invalid command '#{command}'") if invalid? command
@commands[command].execute
end
def invalid?(command)
[email protected]_key? command
end
end
अब हम वर्ग पुनर्संशोधित गया है ऐसी है कि एक अतिरिक्त आदेश बस को आदेश हमारे सशर्त तर्क के साथ-साथ invalid?
विधि को बदलने के बजाय हैश एक अतिरिक्त प्रविष्टि जोड़ने के लिए हमें की आवश्यकता है।
सभी परीक्षण अभी भी पास होना चाहिए और हमने अपना काम लगभग पूरा कर लिया है। एक बार जब हम अलग-अलग आदेशों ड्राइव का परीक्षण तुम वापस इनिशियलाइज़ विधि करने के लिए जाना और इतने की तरह आदेश के लिए कुछ चूक जोड़ सकते हैं:
def initialize(character_creation_command = CharacterCreation.new,
inventory_command = Inventory.new)
@commands = {
"c" => character_creation_command,
"i" => inventory_command
}
end
अंतिम परीक्षण है:
describe GameMenu do
it "Allows you to navigate to character creation" do
character_creation = mock("character creation")
character_creation.should_receive(:execute)
menu = GameMenu.new(character_creation)
menu.execute("c")
end
it "Allows you to display character inventory" do
inventory_command = mock("inventory")
inventory_command.should_receive(:execute)
menu = GameMenu.new(nil, inventory_command)
menu.execute("i")
end
it "Raises an error when an invalid command is entered" do
menu = GameMenu.new(nil, nil)
lambda { menu.execute("invalid command") }.should raise_error(ArgumentError)
end
end
और अंतिम GameMenu
तरह लग रहा है :
class GameMenu
def initialize(character_creation_command = CharacterCreation.new,
inventory_command = Inventory.new)
@commands = {
"c" => character_creation_command,
"i" => inventory_command
}
end
def execute(command)
raise ArgumentError("Invalid command '#{command}'") if invalid? command
@commands[command].execute
end
def invalid?(command)
[email protected]_key? command
end
end
आशा है कि मदद करता है!
ब्रैंडन
+1: टीडीडी का उत्कृष्ट उदाहरण। विस्तृत उत्तर के लिए – Johnsyweb
धन्यवाद। आपने मुझे चबाने और सोचने के लिए बहुत कुछ दिया। एकमात्र चीज जो वास्तव में आपके उदाहरण के बारे में मुझे परेशान कर रही है वह यह है कि गेममेनू प्रारंभकर्ता बहुत सारे आदेश जोड़ने के बाद वास्तव में लंबा हो जाएगा। और अगर यह ट्रैक रखना है कि मेरा नया "शो मैप" कमांड सूची के नीचे 10 पैरामीटर कहता है तो इसका परीक्षण करना आसान होगा। इसके लिए कोई अच्छा समाधान? – Dty
@ डीटी बिल्कुल। मैंने इसे माना था। मैंने सोचा कि इस उदाहरण के लिए यह एक बड़ा सौदा नहीं होगा, लेकिन आपने पुष्टि की है कि यह/हो सकता है। आप इससे निपटने के कुछ तरीके हैं। दिमाग में आने वाला पहला व्यक्ति
register_menu_command
जोड़ना है जिसे कमांड को पंजीकृत करने के लिए बाहरी रूप से बुलाया जा सकता है। दूसरा उस पैरामीटर सूची को _Builder Pattern_ के साथ प्रतिस्थापित करेगा और बस एक मेनूबिल्डर में पास होगा जो हैश उत्पन्न करता है। आप अपने परीक्षण में बिल्डर को कॉन्फ़िगर कर सकते हैं। मैं शायद बिल्डर समाधान पसंद करेंगे। – bcarlso