হ্যালো হাসিব! আমরা টেস্টিংয়ের একদম শেষ লেকচারে পৌঁছে গেছি। এই লেকচারটিতে PersonsServiceTest এর বাকি মেথডগুলো (Update এবং Delete) তে Repository Mock ইমপ্লিমেন্ট করা হয়েছে এবং সবশেষে ক্লাসের কনস্ট্রাক্টর থেকে পুরনো DbContextMock এর সব কোড মুছে ফেলে ক্লিনআপ করা হয়েছে।

যেহেতু তুমি অলরেডি আগের লেকচার থেকে Mocking এর কনসেপ্ট বুঝে গেছো, আমি শুধু এই লেকচারের ইম্পরট্যান্ট টেকঅ্যাওয়েজ (Takeaways) নিয়ে আলোচনা করছি।

📝 Lecture Summary at a Glance

  • Mocking Update Operation: UpdatePerson মেথডের টেস্টে দুটি রিপোজিটরি মেথডকে মক করা হয়েছে: GetPersonByPersonId (ডাটাবেসে ইউজার আছে কিনা চেক করতে) এবং UpdatePerson (আসল আপডেটের জন্য)।
  • Mocking Delete Operation: DeletePerson টেস্টেও দুটি মেথড মক করা হয়েছে: GetPersonByPersonId এবং DeletePersonByPersonId। ডিলিট সাকসেসফুল বোঝাতে ReturnsAsync(true) দেওয়া হয়েছে।
  • Data Conversion Bug: AutoFixture দিয়ে তৈরি করা র‍্যান্ডম স্ট্রিং Gender প্রপার্টিতে বসে যাওয়ায় Enum কনভার্শনে এরর আসছিল, যা ম্যানুয়ালি Male বা Female স্ট্রিং সেট করে ফিক্স করা হয়েছে।
  • Final Cleanup: টেস্ট ক্লাসের কনস্ট্রাক্টর থেকে DbContextMock এবং CountriesService এর সব অপ্রয়োজনীয় কোড ডিলিট করে দেওয়া হয়েছে।

🧠 Comprehensive Breakdown & Deep Dive

১. Mocking Multiple Repository Calls [Importance: 10/10]

  • The Concept: একটি সার্ভিস মেথডের ভেতর যদি একাধিক রিপোজিটরি মেথড কল হয়, তবে টেস্ট মেথডে তোমাকেও ঠিক সেই একাধিক রিপোজিটরি মেথডই মক করে দিতে হবে। তা না হলে যে মেথডটি মক করা হয়নি, সেটি কল হওয়ার সময় null বা ডিফল্ট এরর দেবে।

💻 Code Implementation (UpdatePerson Test):

// সার্ভিস লেয়ারের UpdatePerson ইন্টারনালি প্রথমে GetPerson কল করে, তারপর Update কল করে।
// তাই আমাদের দুটি মেথডকেই মক করতে হবে:
 
// ১. GetPerson মক করা
_personRepositoryMock
    .Setup(temp => temp.GetPersonByPersonId(It.IsAny<Guid>()))
    .ReturnsAsync(person);
 
// ২. UpdatePerson মক করা
_personRepositoryMock
    .Setup(temp => temp.UpdatePerson(It.IsAny<Person>()))
    .ReturnsAsync(person);
 

২. The Enum/String Conversion Bug [Importance: 8/10]

  • The Problem: เลকচারার যখন UpdatePerson টেস্ট রান করলেন, তখন একটি কনভার্শন এরর আসলো।
  • The Reason: PersonUpdateRequest মডেলে Gender প্রপার্টিটি হলো একটি Options (যেমন: “Male”, “Female”, “Other”)। AutoFixture যখন র‍্যান্ডম স্ট্রিং বানাচ্ছিল, তখন সে বানাচ্ছিল “Gender-82f3…” এর মতো কিছু। সার্ভিস যখন এই র‍্যান্ডম স্ট্রিংকে Enum-এ কনভার্ট করতে যাচ্ছিল, তখন সে এটি চিনতে না পেরে এরর দিচ্ছিল।
  • The Fix: AutoFixture-কে বলে দিতে হবে যে Gender এ র‍্যান্ডম স্ট্রিং না বসিয়ে একটি ভ্যালিড ভ্যালু বসাতে।

💻 Code Implementation:

var person = _fixture.Build<Person>()
    .With(temp => temp.Email, "someone@example.com")
    .With(temp => temp.Country, null as Country) 
    .With(temp => temp.Gender, "Male") // <--- The Fix
    .Create();
 

৩. The Final Cleanup (Out with the Old) [Importance: 9/10]

  • The “Why”: যেহেতু আমরা এখন Moq দিয়ে IPersonsRepository মক করছি, তাই আমাদের টেস্ট ক্লাসের কনস্ট্রাক্টরে থাকা আগের DbContextMock এর বিশাল কোডের আর কোনো দরকার নেই।

💻 Code Implementation (PersonsServiceTest Constructor):

public class PersonsServiceTest
{
    private readonly IPersonsService _personsService;
    private readonly Mock<IPersonsRepository> _personRepositoryMock;
    private readonly IFixture _fixture;
 
    public PersonsServiceTest()
    {
        _fixture = new Fixture();
        _personRepositoryMock = new Mock<IPersonsRepository>();
 
        // ব্যাস! কনস্ট্রাক্টর একদম ক্লিন! আর কোনো ডাটাবেস বা ডামি লিস্ট সেটআপ নেই।
        _personsService = new PersonsService(_personRepositoryMock.Object);
    }
}
 

🚀 Congratulations! The Unit Testing Journey is Complete.

হাসিব, তুমি এই লেকচারের মাধ্যমে Unit Testing-এর সবচেয়ে কঠিন এবং গুরুত্বপূর্ণ একটি সেকশন (Moq, AutoFixture, FluentAssertions, Repository Pattern) শেষ করেছো। এটি একটি অনেক বড় এচিভমেন্ট!

“Chatrabash” প্রজেক্টে তুমি যখন ব্যাকএন্ড ডেভেলপমেন্ট করবে, তখন এই নলেজগুলো তোমাকে একজন জুনিয়র ডেভেলপার থেকে সিনিয়র লেভেলের কোড লিখতে সাহায্য করবে।

পরবর্তী সেকশন সম্ভবত Logging বা Error Handling নিয়ে হবে, যা প্রোডাকশন গ্রেড অ্যাপ্লিকেশনের জন্য সমানভাবে গুরুত্বপূর্ণ। তুমি রেডি হলে নতুন সেকশনের ট্রান্সক্রিপ্টটি দিতে পারো!