পরীক্ষাগুলি এবং উত্পাদন কোডের মধ্যে ধ্রুবকগুলি অনুলিপি করে?


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) ঠিক এখনই ক্লাসের চুক্তি তৈরি করার দরকার নেই।

যখন কোনও শ্রেণির চুক্তিটি যথাযথভাবে সংজ্ঞায়িত না হয়, তখন এর পরীক্ষা করা আমাদের শ্রেণীর প্রকৃতি নিয়ে প্রশ্ন তুলতে পারে, তবে এটি ব্যবহার করে would আমি বলব যে আপনি ক্লাসটির চুক্তিটি আপগ্রেড করবেন না কারণ আপনি এটি পরীক্ষা করছেন; আপনার অন্যান্য কারণে ক্লাসের চুক্তিটি আপগ্রেড করা উচিত, যেমন এটি ডোমেনের জন্য দুর্বল বিমূর্ততা এবং যদি তা না হয় তবে এটি যেমন হয় তেমন পরীক্ষা করে test


4

@ এরিক প্রস্তাবিত - আপনি যা পরীক্ষা করছেন সে সম্পর্কে আপনি পরিষ্কার আছেন তা নিশ্চিত করার ক্ষেত্রে - অবশ্যই আপনার বিবেচনার প্রথম বিষয় হওয়া উচিত।

তবে কী আপনার সিদ্ধান্তটি আপনাকে ধ্রুবকগুলিকে ফ্যাক্টরিংয়ের দিকে নিয়ে যায়, যা আপনার প্রশ্নের আকর্ষণীয় অংশ ছেড়ে দেয় (প্যারাফ্রেসিং) "কেন আমি নকল কোডের জন্য ডুপ্লিকেটিং কনস্ট্যান্টের কেন বাণিজ্য করব?" (আপনি যেখানে "নকল [আউট_ডির + নাম ধাপ" নকল করবেন "সেই বিষয়ে উল্লেখ করেছেন))

আমি বিশ্বাস করি যে (এরিক মন্তব্যের modulo) সবচেয়ে পরিস্থিতিতে কি করতে ডুপ্লিকেট ধ্রুবক সরানোর থেকে সুবিধা। তবে আপনার এমনটি এমনভাবে করা দরকার যাতে কোড নকল হয় না । আপনার বিশেষ উদাহরণে, এটি সহজ। আপনার উত্পাদন কোডে "কাঁচা" স্ট্রিং হিসাবে কোনও পাথের সাথে व्यवहार করার পরিবর্তে কোনও পাথকে একটি পথ হিসাবে বিবেচনা করুন। স্ট্রিং কনটেনটেশনের চেয়ে পাথের উপাদানগুলিতে যোগ দেওয়ার এটি আরও শক্তিশালী উপায়:

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

অন্যদিকে আপনার পরীক্ষার কোডে, আমি এই জাতীয় কিছু প্রস্তাব করব। এখানে, জোরটি দেখানো হচ্ছে যে আপনার একটি পথ রয়েছে এবং আপনি একটি পাতার ফাইলের নাম "প্লাগ ইন" করছেন:

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

এটি হ'ল ভাষা উপাদানগুলির আরও চিন্তাশীল নির্বাচন করে আপনি স্বয়ংক্রিয়ভাবে কোড সদৃশতা এড়াতে পারবেন। (সব সময় নয়, তবে আমার অভিজ্ঞতায় খুব প্রায়ই)


1

আমি এরিক Eidদতের উত্তরের সাথে একমত, তবে তৃতীয় বিকল্প রয়েছে: পরীক্ষায় ধ্রুবকটি আটকে দাও, তাই আপনি পরীক্ষার কোডটিতে ধ্রুবকের মান পরিবর্তন করলেও পরীক্ষাটি পাস হয়।

( পাইথন ইউনিটেস্টে ধ্রুবক স্টাবিং দেখুন )

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 "! = 'অনন্য_আপনার_আপনার_পরে_" "দেখেছি কিনা তা নিশ্চিত করে নিচ্ছি এবং সেখানে বিবৃতিটি পরীক্ষায় withফিরিয়ে আনব সুতরাং এটি আবার পাস।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.