আমার উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি পরীক্ষা করা উচিত?


30

ধরুন আমার কাছে বেস ক্লাসের কর্মচারী থেকে প্রাপ্ত একটি ক্লাস ম্যানেজার রয়েছে এবং সেই কর্মচারীর একটি পদ্ধতি getEmail আছে ( যা ম্যানেজারের উত্তরাধিকার সূত্রে প্রাপ্ত ) । আমার কি পরীক্ষা করা উচিত যে কোনও পরিচালকের getEmail () পদ্ধতির আচরণটি আসলে একজন কর্মীর মতোই?

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

(নোট করুন যে টেস্টিং ম্যানেজার :: getEmail () পদ্ধতি ম্যানেজার :: getEmail () তৈরি / ওভাররাইড না হওয়া পর্যন্ত কোড কভারেজ (বা প্রকৃতপক্ষে কোনও কোড মানের মেট্রিক (?)) উন্নত করে না ) )

(যদি উত্তরটি "হ্যাঁ" হয়, তবে বেস এবং উত্পন্ন শ্রেণীর মধ্যে ভাগ করা টেস্ট পরিচালনা করার পদ্ধতি সম্পর্কে কীভাবে যেতে হবে সে সম্পর্কে কিছু তথ্য কার্যকর হবে))

প্রশ্নের সমতুল্য সূত্র:

যদি একটি উত্পন্ন শ্রেণি একটি বেস শ্রেণীর থেকে কোনও পদ্ধতি উত্তরাধিকার সূত্রে প্রাপ্ত হয় তবে আপনি উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিটি আশা করছেন কিনা তা আপনি কীভাবে (পরীক্ষা) প্রকাশ করবেন:

  1. বেসটি ঠিক এখন যেমন করে তেমন আচরণ করুন (যদি বেসের আচরণ পরিবর্তন হয় তবে উত্পন্ন পদ্ধতির আচরণটি পরিবর্তন করে না);
  2. সর্বকালের জন্য বেসের মতো ঠিক একই আচরণ করুন (যদি বেস শ্রেণীর আচরণ পরিবর্তন হয়, উত্পন্ন শ্রেণীর আচরণও পরিবর্তিত হয়); অথবা
  3. এটি চাই তবে আচরণ করুন (আপনি এই পদ্ধতির আচরণের বিষয়ে চিন্তা করবেন না কারণ আপনি কখনই এটি কল করেন না)।

1
আইএমও থেকে কোনও Managerশ্রেণি প্রাপ্ত Employeeহওয়া প্রথম বড় ভুল ছিল।
কোডসইনচওস

4
@ কোডস ইনচাউস হ্যাঁ, এটি একটি খারাপ উদাহরণ হতে পারে। আপনার যখন উত্তরাধিকার থাকবে তখনই একই সমস্যাটি প্রযোজ্য।
এমজেএস

1
এমনকি আপনাকে পদ্ধতিটি ওভাররাইড করার দরকার নেই। বেস ক্লাসের পদ্ধতিটি ওভাররাইড হওয়া অন্য ইনস্ট্যান্স পদ্ধতিগুলিকে কল করতে পারে এবং পদ্ধতির জন্য একই উত্স কোডটি কার্যকর করা এখনও বিভিন্ন আচরণ তৈরি করে।
gnasher729

উত্তর:


23

আমি এখানে ব্যবহারিক পদ্ধতিটি গ্রহণ করব: ভবিষ্যতে যদি কেউ, ম্যানেজার :: গেটমাইলকে ওভাররাইড করে, তবে নতুন পদ্ধতির জন্য পরীক্ষার কোড সরবরাহ করা বিকাশকারীর দায়িত্ব।

অবশ্যই এটি কেবলমাত্র বৈধ যদি Manager::getEmailসত্যিকারের মতো একই কোড পাথ থাকে Employee::getEmail! এমনকি যদি পদ্ধতিটি ওভাররাইড না করা হয় তবে এটি অন্যরকম আচরণ করতে পারে:

  • Employee::getEmailকিছু সুরক্ষিত ভার্চুয়াল পেরেছিলাম getInternalEmailযা হয় ওভাররাইড করা Manager
  • Employee::getEmailকিছু অভ্যন্তরীণ অবস্থা অ্যাক্সেস করতে পারে (উদাহরণস্বরূপ কিছু ক্ষেত্র _email), যা দুটি বাস্তবায়নের ক্ষেত্রে পৃথক Employeeহতে পারে : উদাহরণস্বরূপ, এর ডিফল্ট বাস্তবায়নটি _emailসর্বদা তা নিশ্চিত করতে পারে firstname.lastname@example.comতবে Managerমেল ঠিকানা বরাদ্দকরণে এটি আরও নমনীয়।

এই ধরনের ক্ষেত্রে, এটি সম্ভব হয় যে কোনও বাগ নিজেই উদ্ভাসিত হয় Manager::getEmail, যদিও পদ্ধতিটির বাস্তবায়ন একই হয়। সেক্ষেত্রে Manager::getEmailপৃথকভাবে পরীক্ষা করা অর্থবোধ করতে পারে।


14

আমি করতাম

যদি আপনি "ভালভাবে ভাবছেন তবে এটি কেবলমাত্র কর্মচারীকে কল করুন: getEmail () কারণ আমি এটিকে ওভাররাইড করি না, সুতরাং আমাকে ম্যানেজার :: গেটমেইল () পরীক্ষা করার দরকার নেই তবে আপনি প্রকৃতপক্ষে আচরণটি পরীক্ষা করছেন না অফ ম্যানেজার :: getEmail ()।

আমি কেবলমাত্র ব্যবস্থাপক :: getEmail () কী করা উচিত তা ভেবে দেখব, এটি উত্তরাধিকারসূত্রে প্রাপ্ত বা ওভাররাইড করা হয়েছে কিনা not যদি ম্যানেজার :: getEmail () এর আচরণটি কর্মচারী :: getMail () যা ফেরত দেয় তা ফিরিয়ে দেওয়া উচিত, তবে এটি পরীক্ষা। যদি আচরণটি "গোলাপী @ ইউনিকর্নস.কম" ফিরে আসে, তবে এটিই পরীক্ষা। এটি উত্তরাধিকারী দ্বারা প্রয়োগ করা হয়েছে বা অগ্রাহ্য করা তা বিবেচ্য নয়।

কী ব্যাপার তা হ'ল, যদি এটি ভবিষ্যতে পরিবর্তন হয় তবে আপনার পরীক্ষাটি এটি ধরবে এবং আপনি জানেন যে কোনও কিছু ভেঙে গেছে বা পুনর্বিবেচনা করা দরকার।

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

মতামতগুলি ভিন্ন হতে পারে, আমি মনে করি ডিগার এবং হেইঞ্জি তার বিপরীতে যুক্তিসঙ্গত ন্যায়সঙ্গততা দিয়েছে।


1
আমি এই যুক্তিটি পছন্দ করি যে শ্রেণিটি যেভাবে নির্মিত হবে তার আচরণগত পরীক্ষাটি orthogonal। যদিও উত্তরাধিকার সম্পূর্ণরূপে উপেক্ষা করা কিছুটা মজাদার বলে মনে হচ্ছে না। (এবং যদি আপনার উত্তরাধিকার প্রচুর পরিমাণে থাকে তবে আপনি কীভাবে ভাগ করা পরীক্ষাগুলি পরিচালনা করবেন?)
এমজেএস

1
ভাল করা. ম্যানেজার উত্তরাধিকারসূত্রে প্রাপ্ত পদ্ধতিটি ব্যবহার করছেন বলে কোনওভাবেই এটি পরীক্ষা করা উচিত নয়। আমার এক দুর্দান্ত নেতৃত্ব একবার বলেছিল, "যদি এটি পরীক্ষা না করা হয় তবে এটি ভেঙে গেছে।" সেই লক্ষ্যে, আপনি যদি কোড চেক-ইন-এ প্রয়োজনীয় কর্মচারী এবং ম্যানেজারের জন্য পরীক্ষা করেন তবে আপনি নিশ্চিত হন যে বিকাশকারীরা ম্যানেজারের জন্য নতুন কোডে চেক করলে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতির আচরণকে পরিবর্তন করতে পারে নতুন আচরণ প্রতিফলিত করার জন্য পরীক্ষাটি ঠিক করে দেবে । বা আপনার দরজায় কড়া নাড়তে আসা।
হারিকেনমিচ

2
আপনি সত্যিই পরিচালক ক্লাস পরীক্ষা করতে চান। এটি কর্মচারীর একটি সাবক্লাস এবং গেটমেল () উত্তরাধিকারের উপর নির্ভর করে বাস্তবায়ন করা হয়, এটি কেবলমাত্র একটি বাস্তবায়নের বিশদ যা ইউনিট পরীক্ষাগুলি তৈরি করার সময় আপনাকে উপেক্ষা করা উচিত। পরের মাসে আপনি জানতে পারেন যে কর্মচারীর কাছ থেকে উত্তরাধিকারী হওয়া ম্যানেজারটি একটি খারাপ ধারণা ছিল এবং আপনি পুরো উত্তরাধিকারের কাঠামোটি প্রতিস্থাপন করেন এবং সমস্ত পদ্ধতি পুনরায় সংশোধন করেন। আপনার ইউনিট পরীক্ষাগুলি কোনও সমস্যা ছাড়াই আপনার কোড পরীক্ষা করা চালিয়ে যাওয়া উচিত।
gnasher729

5

ইউনিট এটি পরীক্ষা করবেন না। এটি কার্যকরী / গ্রহণযোগ্যতা পরীক্ষা করুন।

ইউনিট পরীক্ষাগুলি প্রতিটি বাস্তবায়ন পরীক্ষা করে দেখা উচিত, আপনি যদি নতুন বাস্তবায়ন সরবরাহ না করে থাকেন তবে ডিআরওয়াই নীতি অনুসারে থাকুন। আপনি যদি এখানে কিছু প্রচেষ্টা ব্যয় করতে চান তবে আপনি মূল ইউনিট পরীক্ষাটি বাড়িয়ে নিতে পারেন। আপনি যদি পদ্ধতিটি ওভাররাইড করেন তবেই আপনার ইউনিট পরীক্ষা লেখা উচিত।

একই সময়ে, কার্যকরী / গ্রহণযোগ্যতা পরীক্ষার মাধ্যমে নিশ্চিত হওয়া উচিত যে দিনের শেষে আপনার কোডের সমস্তটি যা অনুমান করা উচিত তা করে এবং আশা করি উত্তরাধিকার থেকে কোনও অদ্ভুততা ধরে ফেলবে।


4

টিডিডির জন্য রবার্ট মার্টিনের বিধিগুলি হ'ল :

  1. ব্যর্থ ইউনিট পরীক্ষার পাস করা না হলে আপনাকে কোনও প্রোডাকশন কোড লেখার অনুমতি নেই।
  2. ব্যর্থ হওয়ার পক্ষে পর্যাপ্ত পরিমাণের চেয়ে আপনাকে কোনও ইউনিট পরীক্ষার আর কোনও লেখার অনুমতি নেই; এবং সংকলন ব্যর্থতা ব্যর্থতা।
  3. একটি ব্যর্থ ইউনিট পরীক্ষায় পাস করার জন্য আপনার পক্ষে আর কোনও প্রোডাকশন কোড লেখার অনুমতি নেই।

আপনি যদি এই বিধিগুলি অনুসরণ করেন তবে আপনি এই প্রশ্নটি করার মতো অবস্থানে যেতে পারবেন না। যদি getEmailপদ্ধতিটি পরীক্ষা করার প্রয়োজন হয় তবে এটি পরীক্ষা করা হত।


3

হ্যাঁ, আপনার উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি পরীক্ষা করা উচিত কারণ ভবিষ্যতে সেগুলি ওভাররাইড হতে পারে । এছাড়াও, উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি ভার্চুয়াল পদ্ধতিগুলি কল করতে পারে যা ওভাররাইড করা হয় , যা অ-ওভাররাইড উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিটির আচরণকে পরিবর্তন করে।

আমি এটি পরীক্ষা করার উপায়টি হ'ল (সম্ভবত বিমূর্ত) বেস বর্গ বা ইন্টারফেসটি পরীক্ষা করার জন্য একটি বিমূর্ত শ্রেণি তৈরি করে (সি # তে নুনিট ব্যবহার করে):

public abstract class EmployeeTests
{
    protected abstract Employee CreateInstance(string name, int age);

    [Test]
    public void GetEmail_ReturnsValidEmailAddress()
    {
        // Given
        var sut = CreateInstance("John Doe", 20);

        // When
        string email = sut.GetEmail();

        // Then
        Assert.IsTrue(Helper.IsValidEmail(email));
    }
}

তারপরে, আমার কাছে নির্দিষ্ট শ্রেণীর পরীক্ষাগুলি রয়েছে Managerএবং কর্মচারীর পরীক্ষাগুলি এভাবে সংহত করে:

[TestFixture]
public class ManagerTests
{
    // Other tests.

    [TestFixture]
    public class ManagerEmployeeTests : EmployeeTests
    {
        protected override Employee CreateInstance(string name, int age);
        {
            return new Manager(name, age);
        }
    }
}

লিসকোভের প্রতিস্থাপনের নীতিটি যেহেতু আমি এটি করতে পারি তার কারণ: Employeeকোনও Managerবস্তুর পাস করার পরেও পরীক্ষাগুলি পাস করা উচিত , যেহেতু এটি থেকে প্রাপ্ত Employee। সুতরাং আমাকে আমার পরীক্ষাগুলি কেবল একবার লিখতে হবে এবং এগুলি ইন্টারফেস বা বেস ক্লাসের সমস্ত সম্ভাব্য প্রয়োগের জন্য কাজ করে যাচাই করতে পারে।


লিসকোভের প্রতিস্থাপনের নীতিটি ভাল পয়েন্ট, আপনি ঠিক বলেছেন যে এটি যদি ধরে থাকে তবে ডাইরিভড ক্লাসটি সমস্ত বেস ক্লাসের পরীক্ষা পাস করবে। তবে, এলএসপি প্রায়শই লঙ্ঘন করা হয়, যার মধ্যে xUnit এর setUp()পদ্ধতি নিজেই রয়েছে! এবং প্রায় প্রতিটি ওয়েব এমভিসি কাঠামোতে একটি "সূচক" পদ্ধতি ওভাররাইড জড়িত জড়িত এলএসপিও ভেঙে দেয়, যা মূলত এগুলি সমস্তই।
এমজেএস

এটি একেবারে সঠিক উত্তর - শুনেছি এটি "বিমূর্ত পরীক্ষার প্যাটার্ন" বলে। কৌতূহলের বাইরে, কেন কেবল পরীক্ষার মাধ্যমে মিক্স-ইন করার চেয়ে নেস্টেড ক্লাস ব্যবহার করবেন class ManagerTests : ExployeeTests? (অর্থাত্ পরীক্ষার অধীনে ক্লাসগুলির উত্তরাধিকার মিরর করে দেওয়া the) ফলাফলগুলি দেখাতে সহায়তা করার জন্য এটি কি মূলত নান্দনিকতা?
লূক উশারউড

2

আমার কি পরীক্ষা করা উচিত যে কোনও পরিচালকের getEmail () পদ্ধতির আচরণটি আসলে একজন কর্মীর মতোই?

আমি বলব না যে এটি আমার মতে পুনরাবৃত্তি পরীক্ষা হবে আমি কর্মচারী পরীক্ষায় একবার পরীক্ষা করব এবং এটি হবে।

এই পরীক্ষাগুলি লেখার সময় আচরণটি একই রকম হবে তবে অবশ্যই ভবিষ্যতে কোনও সময় কেউ এই পদ্ধতিটিকে ওভাররাইড করতে পারে, তার আচরণ পরিবর্তন করতে পারে

যদি পদ্ধতিটি ওভাররাইড হয় তবে আপনার ওভাররাইড করা আচরণটি পরীক্ষা করতে নতুন পরীক্ষা দরকার। ওভাররাইডিং getEmail()পদ্ধতিটি প্রয়োগ করা ব্যক্তির কাজ এটি ।


1

না, আপনাকে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি পরীক্ষা করার দরকার নেই। এই পদ্ধতির উপর নির্ভরশীল ক্লাস এবং তাদের পরীক্ষার কেসগুলি আচরণ পরিবর্তিত হলে যেকোনোভাবে ভেঙে যাবে Manager

নিম্নলিখিত দৃশ্যের কথা চিন্তা করুন: ইমেল ঠিকানাটি ফার্স্টনাম.লাস্টনেম@example.com হিসাবে একত্রিত হয়:

class Employee{
    String firstname, lastname;
    String getEmail() { 
        return firstname + "." + lastname + "@example.com";
    }
}

আপনি ইউনিট এটি পরীক্ষা করেছেন এবং এটি আপনার জন্য দুর্দান্ত কাজ করে Employee। আপনি একটি ক্লাসও তৈরি করেছেন Manager:

class Manager extends Employee { /* nothing different in email generation */ }

এখন আপনার কাছে একটি ক্লাস রয়েছে ManagerSortযা পরিচালকদের তাদের ইমেল ঠিকানার ভিত্তিতে একটি তালিকাতে সাজান। আপনার নিজেরাই মনে করেন যে ইমেল জেনারেশন এর মতো Employee:

class ManagerSort {
    void sortManagers(Manager[] managerArrayToBeSorted)
        // sort based on email address omitted
    }
}

আপনি আপনার জন্য একটি পরীক্ষা লিখুন ManagerSort:

void testManagerSort() {
    Manager[] managers = ... // build random manager list
    ManagerSort.sortManagers(managers);

    Manager[] expected = ... // expected result
    assertEquals(expected, managers); // check the result
}

সবকিছু ঠিকঠাক কাজ করে। এখন কেউ এসে getEmail()পদ্ধতিটি ওভাররাইড করে :

class Manager extends Employee {
    String getEmail(){
        // managers should have their lastname and firstname order changed
        return lastname + "." + firstname + "@example.com";
    }
}

এখন, কি হয়? তোমার testManagerSort()ব্যর্থ হবে কারণ getEmail()এর Managerওভাররাইড করা হয়েছিল। আপনি এই সমস্যাটি তদন্ত করবেন এবং কারণটি আবিষ্কার করবেন। এবং সমস্ত উত্তরাধিকারসূত্রে প্রাপ্ত পদ্ধতির জন্য পৃথক টেস্টকেস না লিখে।

সুতরাং, আপনার উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি পরীক্ষা করার দরকার নেই।

অন্যথায়, জাভা যেমন, আপনি সব পদ্ধতি থেকে উত্তরাধিকারসূত্রে পরীক্ষা করতে হবে Objectমত toString(), equals()যে ক্লাসে ইত্যাদি।


ইউনিট পরীক্ষাগুলি নিয়ে আপনার চালাক হওয়ার কথা নয়। আপনি বলছেন "আমার এক্স পরীক্ষা করার দরকার নেই কারণ যখন এক্স ব্যর্থ হয়, ওয়াই ব্যর্থ হয়"। তবে ইউনিট পরীক্ষাগুলি আপনার কোডের বাগের অনুমানের উপর ভিত্তি করে। আপনার কোডে বাগ সহ, আপনি কেন ভাবেন যে পরীক্ষাগুলির মধ্যে জটিল সম্পর্কগুলি আপনি যেভাবে প্রত্যাশা করেন সেভাবে কাজ করে?
gnasher729

@ gnasher729 আমি বলি "সাবক্লাসে আমার এক্স পরীক্ষা করার দরকার নেই কারণ এটি সুপারক্লাসের ইউনিট পরীক্ষায় ইতিমধ্যে পরীক্ষা করা হয়েছে "। অবশ্যই আপনি যদি এক্স এর বাস্তবায়ন পরিবর্তন করেন তবে আপনাকে এর জন্য যথাযথ পরীক্ষা লিখতে হবে।
উওও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.