হ্যালো হাসিব! আমরা টেস্টিংয়ের আরেকটি খুবই গুরুত্বপূর্ণ এবং টাইম-সেভিং টুল নিয়ে কথা বলবো এই লেকচারে—AutoFixture

ইউনিট টেস্ট লেখার সময় সবচেয়ে বোরিং কাজ হলো ডামি ডাটা (Dummy Data) বা ফেক অবজেক্ট তৈরি করা। AutoFixture এই বোরিং কাজটাই অটোমেট করে দেয়।

চলো পুরো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত আলোচনা শুরু করি।

📝 Lecture Summary at a Glance

  • The Problem: প্রতিটি ইউনিট টেস্টে ম্যানুয়ালি মডেল অবজেক্ট (যেমন PersonAddRequest) তৈরি করে তাতে ডামি ডাটা ইনপুট দেওয়া অনেক সময়সাপেক্ষ এবং রিপিটেটিভ কাজ।
  • The Solution (AutoFixture): এটি একটি থার্ড-পার্টি লাইব্রেরি যা নিজে থেকেই যেকোনো ক্লাসের অবজেক্ট তৈরি করে তার সবগুলো প্রপার্টিতে র‍্যান্ডম ডামি ডাটা বসিয়ে দেয়।
  • Create<T>(): এই মেথডটি দিয়ে সরাসরি একটি মডেল অবজেক্ট তৈরি করা যায়।
  • Build<T>() & With(): যদি কোনো নির্দিষ্ট প্রপার্টির ভ্যালু নিজে হাতে কাস্টমাইজ করতে হয় (যেমন Email এর ক্ষেত্রে ভ্যালিড ইমেইল ফরম্যাট দেওয়া), তখন Build এর সাথে চেইন করে With মেথড ব্যবহার করতে হয়।

🧠 Comprehensive Breakdown & Deep Dive

১. Setting up AutoFixture [Importance: 9/10]

  • The “Why”: ম্যানুয়ালি ডাটা বানালে তুমি হয়তো সব টেস্টে একই নাম বা একই ইমেইল ব্যবহার করবে। কিন্তু AutoFixture সবসময় সম্পূর্ণ নতুন এবং র‍্যান্ডম ডাটা জেনারেট করে, যার ফলে তোমার মেথডটি বিভিন্ন আনপ্রেডিক্টেবল ডাটার ওপর টেস্ট হওয়ার সুযোগ পায়।

💻 Code Implementation (Setup): টেস্ট প্রজেক্টের টার্মিনালে কমান্ড দিয়ে প্যাকেজটি ইনস্টল করতে হবে:

dotnet add package AutoFixture
 

এরপর তোমার টেস্ট ক্লাসের কনস্ট্রাক্টরে Fixture অবজেক্ট ইনিশিয়ালাইজ করতে হবে:

using AutoFixture;
 
public class PersonsServiceTest
{
    private readonly IFixture _fixture;
 
    public PersonsServiceTest()
    {
        // ১. AutoFixture ইনিশিয়ালাইজ করা
        _fixture = new Fixture(); 
    }
}
 

২. Generating Dummy Data with Create<T>() [Importance: 10/10]

  • The “Why”: যখন তোমার ডাটার কন্টেন্ট নিয়ে মাথাব্যথা নেই, জাস্ট একটি অবজেক্ট দরকার (যেমন PersonName"Name123..." থাকলেও সমস্যা নেই), তখন Create মেথড ব্যবহার করা হয়।

💻 Code Implementation:

// ❌ Old Manual Way:
/*
var request = new PersonAddRequest 
{
    PersonName = "Test Name",
    Email = "test@example.com",
    Gender = GenderOptions.Male
};
*/
 
// ✅ Modern AutoFixture Way:
var request = _fixture.Create<PersonAddRequest>();
 
  • How it works: AutoFixture স্ট্রিংয়ের ক্ষেত্রে প্রপার্টির নাম + একটি GUID বসায় (যেমন PersonName-5c7...), নাম্বারের ক্ষেত্রে র‍্যান্ডম ইন্টিজার এবং Enum-এর ক্ষেত্রে র‍্যান্ডম যেকোনো একটি অপশন বসিয়ে দেয়।

৩. The Validation Error and Customizing with Build<T>() [Importance: 10/10]

  • The “Why”: লেকচারার যখন Create() ব্যবহার করে টেস্ট রান করলেন, তখন টেস্ট ফেইল করলো! কারণ Email প্রপার্টির জন্য AutoFixture একটি ভ্যালু দিয়েছিল এরকম: "Email-9b8..."। কিন্তু তোমার সার্ভিস ক্লাসে নিশ্চয়ই ইমেইল ভ্যালিডেশনের লজিক (Regular Expression) লেখা আছে যা এই ভ্যালুকে রিজেক্ট করে দিয়েছে।
  • The Solution: আমাদের AutoFixture-কে বলতে হবে, “তুমি সব প্রপার্টি নিজে বানাও, কিন্তু Email এর ভ্যালুটা আমি যেটা দেব সেটাই রাখবে।” এই কাজটাই Build এবং With দিয়ে করা হয়।

💻 Code Implementation:

var request = _fixture.Build<PersonAddRequest>()
     // শুধুমাত্র ইমেইল প্রপার্টি ওভাররাইড করা হলো
    .With(temp => temp.Email, "someone@example.com") 
     // সবশেষে অবজেক্ট ক্রিয়েট করা হলো
    .Create(); 
 

(তুমি চাইলে .With একাধিকবার চেইন করে লিখতে পারো একাধিক প্রপার্টি কাস্টমাইজ করার জন্য)।


🚀 Modern Testing Best Practices (AutoFixture Advanced Tips)

১. Injecting AutoFixture directly in xUnit ([Theory]) হাসিব, তুমি যদি কোড আরও ক্লিন করতে চাও, তবে xUnit এবং AutoFixture-এর ইন্টিগ্রেশন প্যাকেজ (AutoFixture.Xunit2) ব্যবহার করতে পারো। এতে তোমার টেস্টের ভেতরে _fixture.Create() লিখতে হবে না। টেস্ট মেথড নিজেই প্যারামিটার হিসেবে ডামি অবজেক্ট রিসিভ করবে!

💻 Pro Tip Implementation:

[Theory, AutoData] // Fact এর বদলে Theory এবং AutoData
public void AddPerson_ProperDetails_ReturnsSuccess(PersonAddRequest request)
{
    // AutoFixture নিজে থেকেই 'request' অবজেক্টটি তৈরি করে প্যারামিটারে পাস করে দিয়েছে!
    
    // শুধু ইমেইল ঠিক করার দরকার হলে:
    request.Email = "valid@test.com";
 
    // Act...
}
 

২. Handling Circular References: EF Core মডেল টেস্ট করার সময় AutoFixture মাঝে মাঝে ইনফিনিট লুপে (Infinite Loop) আটকে গিয়ে StackOverflowException দিতে পারে (যেমন Country এর ভেতর Person আবার Person এর ভেতর Country)। এটি সমাধান করার জন্য কনস্ট্রাক্টরে নিচের লাইনটি অ্যাড করে নেওয়া বেস্ট প্র্যাকটিস:

_fixture = new Fixture();
// সার্কুলার রেফারেন্স ইগনোর করার লজিক
_fixture.Behaviors.Remove(new ThrowingRecursionBehavior());
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
 

পরবর্তী লেকচারে লেকচারার পুরো PersonsServiceTest ক্লাসটিকে AutoFixture দিয়ে রিফ্যাক্টর করবেন। তুমি চাইলে পরের ট্রান্সক্রিপ্টটি দিতে পারো!