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


35

আমি সম্প্রতি কিছু বন্ধুদের সাথে আলোচনা করছিলাম নীচের 2 টি পদ্ধতির মধ্যে কোনটি একই শ্রেণীর অভ্যন্তরীণ পদ্ধতিগুলি থেকে একই শ্রেণীর অভ্যন্তরীণ পদ্ধতিগুলিতে ফিরতি ফলাফল বা কলগুলার পক্ষে সবচেয়ে ভাল।

এটি একটি খুব সরল উদাহরণ। বাস্তবে ফাংশনগুলি আরও জটিল।

উদাহরণ:

public class MyClass
{
     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected int FunctionB()
     {
         return new Random().Next();
     }
}

সুতরাং এটি পরীক্ষা করার জন্য আমাদের কাছে 2 টি পদ্ধতি রয়েছে।

পদ্ধতি 1: পদ্ধতিগুলির কার্যকারিতা প্রতিস্থাপন করতে কার্য এবং ক্রিয়াগুলি ব্যবহার করুন। উদাহরণ:

public class MyClass
{
     public Func<int> FunctionB { get; set; }

     public MyClass()
     {
         FunctionB = FunctionBImpl;
     }

     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected int FunctionBImpl()
     {
         return new Random().Next();
     }
}

[TestClass]
public class MyClassTests
{
    private MyClass _subject;

    [TestInitialize]
    public void Initialize()
    {
        _subject = new MyClass();
    }

    [TestMethod]
    public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
    {
        _subject.FunctionB = () => 1;

        var result = _subject.FunctionA();

        Assert.IsFalse(result);
    }
}

পদ্ধতি 2: সদস্যগুলিকে ভার্চুয়াল তৈরি করুন, শ্রেণিভুক্ত করা এবং উত্পন্ন শ্রেণিতে কার্যকারিতা প্রতিস্থাপনের জন্য কার্য এবং ক্রিয়াগুলি উদাহরণ করুন:

public class MyClass
{     
     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }

     protected virtual int FunctionB()
     {
         return new Random().Next();
     }
}

public class TestableMyClass
{
     public Func<int> FunctionBFunc { get; set; }

     public MyClass()
     {
         FunctionBFunc = base.FunctionB;
     }

     protected override int FunctionB()
     {
         return FunctionBFunc();
     }
}

[TestClass]
public class MyClassTests
{
    private TestableMyClass _subject;

    [TestInitialize]
    public void Initialize()
    {
        _subject = new TestableMyClass();
    }

    [TestMethod]
    public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
    {
        _subject.FunctionBFunc = () => 1;

        var result = _subject.FunctionA();

        Assert.IsFalse(result);
    }
}

আমি জানতে চাই যে আরও ভাল এবং কেন?

আপডেট: দ্রষ্টব্য: ফাংশনবিও সর্বজনীন হতে পারে


আপনার উদাহরণটি সহজ তবে সঠিক নয়। FunctionAএকটি বিল ফেরত দেয় তবে কেবল একটি স্থানীয় ভেরিয়েবল সেট xকরে এবং কোনও কিছুই ফেরত দেয় না।
এরিক পি।

1
এই বিশেষ উদাহরণে, ফাংশনবি public staticতবে ভিন্ন শ্রেণিতে থাকতে পারে ।

কোড পর্যালোচনার জন্য, আপনি আসল কোড এটির একটি সরলিকৃত সংস্করণ নয় পোস্ট করবেন। এফএকিউ দেখুন। এর স্ট্যান্ড হিসাবে, আপনি কোড পর্যালোচনা খুঁজছেন না এমন একটি নির্দিষ্ট প্রশ্ন জিজ্ঞাসা করছেন।
উইনস্টন ইওয়ার্ট

1
FunctionBনকশা ভাঙ্গা। new Random().Next()প্রায় সর্বদা ভুল। আপনার উদাহরণটি ইনজেক্ট করা উচিত Random। ( Randomএটি একটি খারাপভাবে ডিজাইন করা
শ্রেণিও রয়েছে

প্রতিনিধিদের মাধ্যমে আরও সাধারণ নোটে ডিআই পুরোপুরি ঠিক আছে imho
জে কে।

উত্তর:


32

মূল পোস্টার আপডেটের পরে সম্পাদিত।

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

লম্বা সংস্করণটি হ'ল: ব্যক্তিগত / সুরক্ষিত পদ্ধতিগুলি এপিআই-র অংশ নয়, এগুলি মূলত বাস্তবায়ন পছন্দসমূহ, আপনি পর্যালোচনা, আপডেট বা বাইরের কোনও প্রভাব ছাড়াই সম্পূর্ণ ফেলে দিতে পারেন throw

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

সম্পর্কিত সম্পর্কিত আলোচনাটি এখানে দেখুন: https://stackoverflow.com/questions/105007/should-i-test-private-methods-or-only-public-ones

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

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


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

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

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

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

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

11

আমি এই তত্ত্বটির সাবস্ক্রাইব করেছি যে যদি কোনও ফাংশন পরীক্ষা করার জন্য গুরুত্বপূর্ণ হয়, বা প্রতিস্থাপন করা গুরুত্বপূর্ণ হয় তবে এটি পরীক্ষার অধীনে শ্রেণীর ব্যক্তিগত বাস্তবায়ন বিশদ না হয়ে যথেষ্ট গুরুত্বপূর্ণ, তবে একটি পৃথক শ্রেণীর সার্বজনীন বাস্তবায়নের বিশদ হতে পারে ।

সুতরাং আমি যদি আমার একটি দৃশ্যে থাকি

class A 
{
     public B C()
     {
         D();
     }

     private E D();
     {
         // i actually want to control what this produces when I test C()
         // or this is important enough to test on its own
         // and, typically, both of the above
     }
}

তারপরে আমি রিফ্যাক্টর যাচ্ছি।

class A 
{
     ICollaborator collaborator;

     public A(ICollaborator collaborator)
     {
         this.collaborator = collaborator;
     }

     public B C()
     {
         collaborator.D();
     }
}

এখন আমার একটি দৃশ্য আছে যেখানে ডি () স্বতন্ত্রভাবে পরীক্ষামূলক এবং সম্পূর্ণরূপে প্রতিস্থাপনযোগ্য।

সংস্থার মাধ্যম হিসাবে, আমার সহযোগী একই নামস্থান স্তরে বাস নাও করতে পারে । উদাহরণস্বরূপ, যদি AFooCorp.BLL এ থাকে তবে আমার সহযোগী FooCorp.BLL.Clalaborators (বা যে কোনও নামই উপযুক্ত) হিসাবে যেমন গভীর হতে পারে অন্য স্তর। আমার সহযোগী কেবল internalঅ্যাক্সেস মডিফায়ারের মাধ্যমে সমাবেশের ভিতরে দৃশ্যমান হতে পারে , যা আমি আমার ইউনিট টেস্টিং প্রকল্প (গুলি) এর কাছে InternalsVisibleToসমাবেশ বৈশিষ্ট্যের মাধ্যমে প্রকাশ করতে পারি । গ্রহণযোগ্যতাটি হ'ল আপনি যাচাইযোগ্য কোড তৈরির সময় কলকারীদের যতটা উদ্বিগ্ন, তবুও আপনার এপিআই পরিষ্কার রাখতে পারেন।


হ্যাঁ আইকোলবোরেটরের যদি বেশ কয়েকটি পদ্ধতির প্রয়োজন হয়। যদি আপনার কোনও অবজেক্ট থাকে তবে যার একমাত্র কাজ হ'ল আমি কোনও একক পদ্ধতিতে গুটিয়ে ফেলি আমি তার পরিবর্তে এটি কোনও প্রতিনিধি দ্বারা প্রতিস্থাপন করতে দেখি।
জে কে।

কোনও নামী প্রতিনিধি বোধগম্য হয় কিনা বা কোনও ইন্টারফেসটি বোঝায় কিনা তা আপনাকে সিদ্ধান্ত নিতে হবে এবং আমি আপনার পক্ষে সিদ্ধান্ত নেব না। ব্যক্তিগতভাবে, আমি একক (সর্বজনীন) পদ্ধতি ক্লাসে বিরত নই। আরও ছোট যত ভাল তারা বোঝা ক্রমশ সহজ হয়ে ওঠে।
অ্যান্টনি পেগ্রাম

0

মার্টিন কী বলেছে তাতে যোগ করা,

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

আপনি যে দুটি পদ্ধতির উল্লেখ করেছেন তাতে আমার এই উদ্বেগ রয়েছে -

পদ্ধতি 1 - এটি পরীক্ষায় পরীক্ষার আচরণের অধীনে ক্লাসটি পরিবর্তিত করে।

পদ্ধতি 2 - এটি আসলে উত্পাদন কোডটি পরীক্ষা করে না, পরিবর্তে অন্য বাস্তবায়ন পরীক্ষা করে।

সমস্যাটিতে বলা হয়েছে, আমি দেখছি যে ফাংশনবির আউটপুটটি সমান কিনা তা দেখার একমাত্র যুক্তি। উদাহরণস্বরূপ, ফাংশনবি র্যান্ডম মান দেয় যা পরীক্ষা করা শক্ত।

আমি এমন বাস্তববাদী দৃশ্যের প্রত্যাশা করব যেখানে আমরা মাই ক্লাস সেটআপ করতে পারি যাতে ফাংশনবি কী ফিরিয়ে আনবে তা আমরা জানি। তারপরে আমাদের প্রত্যাশিত ফলাফলটি জানা যায়, আমরা ফাংশনএ'র কল করতে পারি এবং প্রকৃত ফলাফলের উপর চাপ দিতে পারি।


3
protectedপ্রায় হিসাবে একই public। শুধুমাত্র privateএবং internalবাস্তবায়ন বিশদ।
কোডসইনচাউস

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

যেহেতু এই উত্পন্ন ক্লাসগুলি বিভিন্ন সমাবেশে থাকতে পারে, তাই তারা তৃতীয় পক্ষের কোডের সাথে প্রকাশিত হবে এবং এইভাবে আপনার শ্রেণীর সার্বজনীন পৃষ্ঠের অংশ। এগুলি পরীক্ষা করার জন্য, আপনি হয় এগুলি তৈরি করতে পারেন internal protected, একটি ব্যক্তিগত প্রতিবিম্ব সহায়ক ব্যবহার করতে পারেন, বা আপনার পরীক্ষার প্রকল্পে একটি উত্পন্ন শ্রেণি তৈরি করতে পারেন।
কোডসইনচাউস

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

0

আমি ব্যক্তিগতভাবে মেথড 1 ব্যবহার করি বা অ্যাকশন বা ফুনসকে সমস্ত পদ্ধতি তৈরি করাই এটি আমার পক্ষে কোড টেস্টিবিলিটির ব্যাপক উন্নতি করেছে। যে কোনও সমাধানের মতোই এই পদ্ধতির সাথে কুফলগুলি রয়েছে:

পেশাদাররা

  1. সাধারণ কোড কাঠামোর জন্য অনুমতি দেয় যেখানে কেবল ইউনিট পরীক্ষার জন্য কোড প্যাটার্নগুলি ব্যবহার করা অতিরিক্ত জটিলতা যুক্ত করতে পারে।
  2. ক্লাসগুলিকে সিল করার অনুমতি দেয় এবং ভার্চুয়াল পদ্ধতিগুলি নির্মূলের জন্য যা মক এর মতো জনপ্রিয় উপহাসের ফ্রেমওয়ার্কগুলির দ্বারা প্রয়োজনীয়। ক্লাস সিল করা এবং ভার্চুয়াল পদ্ধতিগুলি মুছে ফেলা তাদের ইনলাইনিং এবং অন্যান্য সংকলক অপ্টিমাইজেশনের প্রার্থী করে। ( https://msdn.microsoft.com/en-us/library/ff647802.aspx )
  3. ইউনিট পরীক্ষায় ফানক / অ্যাকশন বাস্তবায়নের পরিবর্তে টেস্টাবিলিটি সহজ করে ফানক / অ্যাকশনকে নতুন মান নির্ধারণ করার মতোই সহজ
  4. স্থিতিশীল পদ্ধতিগুলি উপহাস করা যায় না বলে অন্য কোনও পদ্ধতি থেকে স্ট্যাটিক ফানক কল করা হয়েছিল কিনা তা পরীক্ষার অনুমতি দেয়।
  5. কল সাইটগুলিতে কোনও পদ্ধতি কল করার সিনট্যাক্সটি যেহেতু ফানকস / অ্যাকশনে বিদ্যমান পদ্ধতিগুলি রিফ্যাক্টর করা সহজ remains (আপনি যখন কোনও পদ্ধতিকে ফানক / অ্যাকশন দেখুন কনসে রূপান্তর করতে পারবেন না)

কনস

  1. যদি আপনার শ্রেণিটি ফানসিএস / ক্রিয়াকলাপগুলির মতো কোনও উত্তরাধিকারের পথ না থাকে তবে ফানস / অ্যাকশনগুলি ব্যবহার করা যাবে না
  2. ডিফল্ট প্যারামিটার ব্যবহার করতে পারি না। ডিফল্ট পরামিতিগুলির সাথে একটি ফানক তৈরি করা একটি নতুন প্রতিনিধি তৈরি করতে জড়িত যা ব্যবহারের ক্ষেত্রে নির্ভর করে কোডটিকে বিভ্রান্ত করতে পারে
  3. কোনও কিছুর মতো কলিং পদ্ধতিগুলির জন্য নামযুক্ত প্যারামিটার সিনট্যাক্স ব্যবহার করতে পারবেন না (প্রথম নাম: "এস", লাস্টনাম: "কে")
  4. সবচেয়ে বড় কনটি হ'ল আপনার ফানকস এবং অ্যাকশনে 'এই' রেফারেন্সটিতে অ্যাক্সেস নেই এবং ক্লাসের উপর কোনও নির্ভরতা স্পষ্ট করে প্যারামিটার হিসাবে পাস করতে হবে। আপনি সমস্ত নির্ভরতা জানেন বলে এটি ভাল তবে আপনার ফানকের উপর নির্ভর করে এমন অনেকগুলি বৈশিষ্ট্য থাকলে আপনার পক্ষে খারাপ। আপনার মাইলেজটি আপনার ব্যবহারের ক্ষেত্রে ভিত্তিতে পৃথক হবে।

সুতরাং সংক্ষেপে বলতে গেলে, ইউনিট পরীক্ষার জন্য ফানকস এবং অ্যাকশনগুলি ব্যবহার করা দুর্দান্ত তবে যদি আপনি জানেন যে আপনার ক্লাসগুলি কখনই ওভাররাইড হবে না।

এছাড়াও, আমি সাধারণত ফানকসের জন্য বৈশিষ্ট্য তৈরি করি না তবে এগুলিতে সরাসরি ইনলাইন করি

public class MyClass
{
     public Func<int> FunctionB = () => new Random().Next();

     public bool FunctionA()
     {
         return FunctionB() % 2 == 0;
     }
}

আশাকরি এটা সাহায্য করবে!


-1

মোক এটি ব্যবহার সম্ভব। নিউজ: https://www.nuget.org/packages/moq/

এবং আমাকে বিশ্বাস করুন এটি মোটামুটি সহজ এবং জ্ঞান করে।

public class SomeClass
{
    public SomeClass(int a) { }

    public void A()
    {
        B();
    }

    public virtual void B()
    {

    }
}

[TestFixture]
public class Test
{
    [Test]
    public void Test_A_Calls_B()
    {
        var mockedObject = new Mock<SomeClass>(5); // You can also specify constructor arguments.
        //You can also setup what a function can return.
        var obj = mockedObject.Object;
        obj.A();

        Mock.Get(obj).Verify(x=>x.B(),Times.AtLeastOnce);//This test passes
    }
}

মোককে ওভাররাইড করতে পদ্ধতি ভার্চুয়াল দরকার needs

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