परीक्षण और उत्पादन कोड के बीच दोहराव स्थिरांक?


20

क्या परीक्षणों और वास्तविक कोड के बीच डेटा की नकल करना अच्छा है या बुरा? उदाहरण के लिए, मान लीजिए कि मेरे पास एक पायथन वर्ग है FooSaverजो किसी विशेष निर्देशिका के साथ फ़ाइलों को किसी निर्देशिका में सहेजता है:

class FooSaver(object):
  def __init__(self, out_dir):
    self.out_dir = out_dir

  def _save_foo_named(self, type_, name):
    to_save = None
    if type_ == FOOTYPE_A:
      to_save = make_footype_a()
    elif type == FOOTYPE_B:
      to_save = make_footype_b()
    # etc, repeated
    with open(self.out_dir + name, "w") as f:
      f.write(str(to_save))

  def save_type_a(self):
    self._save_foo_named(a, "a.foo_file")

  def save_type_b(self):
    self._save_foo_named(b, "b.foo_file")

अब अपने परीक्षण में मैं यह सुनिश्चित करना चाहूंगा कि ये सभी फाइलें बनाई गई थीं, इसलिए मैं कुछ इस तरह कहना चाहता हूं:

foo = FooSaver("/tmp/special_name")
foo.save_type_a()
foo.save_type_b()

self.assertTrue(os.path.isfile("/tmp/special_name/a.foo_file"))
self.assertTrue(os.path.isfile("/tmp/special_name/b.foo_file"))

यद्यपि यह दो स्थानों पर फ़ाइल नाम को दोहराता है, मुझे लगता है कि यह अच्छा है: यह मुझे लिखने के लिए मजबूर करता है कि मैं दूसरे छोर से बाहर आने की उम्मीद करता हूं, यह टाइपोस के खिलाफ सुरक्षा की एक परत जोड़ता है, और आम तौर पर मुझे विश्वास दिलाता है कि चीजें काम कर रही हैं जैसा मैं उम्मीद करता हूं। मुझे पता है कि अगर मैं भविष्य में बदलता हूं तो मुझे अपने परीक्षणों में कुछ खोज-और- परिवर्तन a.foo_fileकरने होंगे type_a.foo_file, लेकिन मुझे नहीं लगता कि यह बहुत बड़ी बात है। यदि मेरे पास कोड और परीक्षणों के बारे में मेरी समझ है, तो यह सुनिश्चित करने के बदले कि मैं परीक्षण को अपडेट करना भूल जाऊं, मेरे पास कुछ गलत सकारात्मक बातें होंगी।

एक सहकर्मी को लगता है कि यह दोहराव बुरा है, और मैंने सिफारिश की कि मैं दोनों पक्षों को इस तरह से मना कर दूं:

class FooSaver(object):
  A_FILENAME = "a.foo_file"
  B_FILENAME = "b.foo_file"

  # as before...

  def save_type_a(self):
    self._save_foo_named(a, self.A_FILENAME)

  def save_type_b(self):
    self._save_foo_named(b, self.B_FILENAME)

और परीक्षण में:

self.assertTrue(os.path.isfile("/tmp/special_name/" + FooSaver.A_FILENAME))
self.assertTrue(os.path.isfile("/tmp/special_name/" + FooSaver.B_FILENAME))

मुझे यह पसंद नहीं है क्योंकि इससे मुझे विश्वास नहीं हो रहा है कि कोड वही कर रहा है जिसकी मुझे उम्मीद थी --- मैंने अभी out_dir + nameप्रोडक्शन साइड और टेस्ट साइड दोनों पर स्टेप डुप्लिकेट किया है । यह +स्ट्रिंग्स पर काम करने की मेरी समझ में एक त्रुटि को उजागर नहीं करेगा , और यह टाइपोस को नहीं पकड़ेगा।

दूसरी ओर, यह उन तार को दो बार लिखने की तुलना में स्पष्ट रूप से कम भंगुर है, और यह मुझे उस तरह से दो फ़ाइलों में डेटा की नकल करने के लिए थोड़ा गलत लगता है।

क्या यहाँ एक स्पष्ट मिसाल है? क्या परीक्षण और उत्पादन कोड में स्थिरांक की नकल करना ठीक है, या क्या यह बहुत भंगुर है?

जवाबों:


16

मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप क्या परीक्षण करना चाहते हैं, जो कक्षा के अनुबंध का है।

वर्ग के अनुबंध ठीक है FooSaverउत्पन्न करता है a.foo_fileऔर b.foo_fileकिसी विशेष स्थान में है, तो आप सीधे उस परीक्षण, यानी परीक्षण में स्थिरांक नकल करना चाहिए।

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

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

रिफैक्टरिंग के दौरान वर्ग के अनुबंध को बदलना भी उचित है, उदाहरण के लिए, इसके अमूर्त स्तर को समय के साथ बढ़ाया जाना। सबसे पहले, यह एक विशेष अस्थायी स्थान में दो विशिष्ट फ़ाइल के बारे में है, लेकिन समय के साथ, आप पा सकते हैं अतिरिक्त अमूर्त चेतावनी दी है। ऐसे समय में, कक्षा के अनुबंध के साथ तालमेल रखने के लिए परीक्षणों को बदल दें। कक्षा के अनुबंध को अभी खत्म करने की आवश्यकता नहीं है क्योंकि आप इसे (YAGNI) का परीक्षण कर रहे हैं।

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


4

@Erik ने जो सुझाव दिया है - यह सुनिश्चित करने के संदर्भ में कि आप जो परीक्षण कर रहे हैं, उस पर आप स्पष्ट हैं - निश्चित रूप से आपका पहला विचार होना चाहिए।

लेकिन क्या आपके निर्णय से आपको स्थिरांक को हटाने की दिशा में ले जाना चाहिए, जो आपके प्रश्न का दिलचस्प हिस्सा छोड़ देता है (पैराफ्रेसिंग) "मुझे कोड को डुप्लिकेट करने के लिए स्थिरांक को बंद करने का व्यापार क्यों करना चाहिए?"। (जहाँ आप "डुप्लिकेट [ing] out_dir + name step" के बारे में बात करते हैं।)

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

os.path.join(self.out_dir, name)

दूसरी ओर आपके परीक्षण कोड में, मैं कुछ इस तरह की सिफारिश करूंगा। यहां, जोर दिखा रहा है कि आपके पास एक रास्ता है और आप एक पत्ती फ़ाइल नाम में "प्लग इन" कर रहे हैं:

self.assertTrue(os.path.isfile("/tmp/special_name/{0}".format(FooSaver.A_FILENAME)))

यही है, भाषा तत्वों के अधिक विचारशील चयन से, आप स्वचालित रूप से कोड दोहराव से बच सकते हैं। (हर समय नहीं, लेकिन मेरे अनुभव में बहुत बार।)


1

मैं एरिक ईड्ट के उत्तर से सहमत हूं, लेकिन एक तीसरा विकल्प है: परीक्षण में स्थिर होना, इसलिए परीक्षण पास हो जाता है, भले ही आप उत्पादन कोड में निरंतरता के मूल्य को बदलते हों।

( अजगरों को स्थिर रूप से स्थिर देखना देखें )

foo = FooSaver("/tmp/special_name")
foo.save_type_a()
foo.save_type_b()

with mock.patch.object(FooSaver, 'A_FILENAME', 'unique_to_your_test_a'):
  self.assertTrue(os.path.isfile("/tmp/special_name/unique_to_your_test_a"))
with mock.patch.object(FooSaver, 'B_FILENAME', 'unique_to_your_test_b'):
  self.assertTrue(os.path.isfile("/tmp/special_name/unique_to_your_test_b"))

और इस तरह की चीजें करते समय मैं आमतौर पर एक पवित्रता परीक्षण करना सुनिश्चित करता हूं, जहां मैं withबयान के बिना परीक्षण चलाता हूं और सुनिश्चित करता हूं कि मुझे "'a.foo_file'! = 'Unique_to_your_test_a' दिखाई देता है, फिर withकथन को परीक्षण में वापस रखें! तो यह फिर से गुजरता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.