হ্যালো হাসিব! আমরা Controller টেস্টিংয়ের আরেকটি রিয়েল-ওয়ার্ল্ড সিনারিওতে চলে এসেছি।
আগের লেকচারে আমরা Index মেথড (GET রিকোয়েস্ট) টেস্ট করেছিলাম, যা খুব সিম্পল ছিল। কিন্তু এই লেকচারে আমরা Create মেথড (POST রিকোয়েস্ট) টেস্ট করবো। POST রিকোয়েস্টে সাধারণত ডাটা ইনসার্ট করা হয় এবং এখানে Model Validation (ModelState) এর একটি বড় ভূমিকা থাকে।
চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত পোস্টমর্টেম করে ফেলি।
📝 Lecture Summary at a Glance
- Two Scenarios:
Create(POST) মেথডের জন্য দুটি টেস্ট কেস লেখা হয়েছে: ১. যখন মডেলে এরর থাকে (InvalidModelState) - তখন এটি একই View ফেরত দেয়। ২. যখন মডেল ভ্যালিড থাকে (No errors) - তখন এটি সাকসেসফুলি ডাটা সেভ করেIndexপেজে রিডাইরেক্ট করে। - Mocking Dependencies:
Createমেথডটি ইন্টারনালিCountriesService.GetAllCountriesএবংPersonsService.AddPersonকল করে, তাই টেস্টের Arrange ফেজে এই দুটোকেই মক করা হয়েছে। - Injecting Model Errors: ইউনিট টেস্টে ASP.NET Core-এর ডিফল্ট মডেল বাইন্ডার কাজ করে না, তাই
_personsController.ModelState.AddModelError()দিয়ে ম্যানুয়ালি এরর পুশ করে ইনভ্যালিড সিনারিও তৈরি করা হয়েছে। - Testing Redirects: যখন মেথড সাকসেসফুলি কাজ শেষ করে অন্য পেজে রিডাইরেক্ট করে, তখন
RedirectToActionResultটাইপ চেক করে তারActionName(“Index”) ভেরিফাই করা হয়েছে।
🧠 Comprehensive Breakdown & Deep Dive
১. Scenario 1: Invalid Model State [Importance: 9/10]
- The “Why”: একজন ইউজার যদি ফর্ম সাবমিট করার সময় নাম ফাঁকা রাখে, তবে Controller-এর
ModelState.IsValidপ্রপার্টিfalseহয়ে যায় এবং ইউজারকে এরর মেসেজসহ আবার একই পেজ দেখানো হয়। আমরা এটাই টেস্ট করতে চাই। - The Trick: টেস্টিং এনভায়রনমেন্টে
ModelStateনিজে নিজে পপুলেট হয় না। তাই আমাদের কোড দিয়ে জোর করে একটি এরর ঢোকাতে হয়।
💻 Code Implementation:
[Fact]
public async Task Create_IfModelErrors_ToReturnCreateView()
{
// Arrange: Mock setup...
PersonAddRequest request = _fixture.Create<PersonAddRequest>();
// The Trick: ম্যানুয়ালি মডেলে এরর পুশ করা
_personsController.ModelState.AddModelError("PersonName", "Person Name can't be blank");
// Act
IActionResult result = await _personsController.Create(request);
// Assert: চেক করা যে এটি ViewResult ফেরত দিয়েছে কিনা
ViewResult viewResult = Assert.IsType<ViewResult>(result);
// চেক করা যে একই মডেল ডাটা আবার ভিউতে পাঠানো হয়েছে কিনা
viewResult.ViewData.Model.Should().BeAssignableTo<PersonAddRequest>();
viewResult.ViewData.Model.Should().BeEquivalentTo(request);
}
২. Scenario 2: Valid Model State & Redirection [Importance: 10/10]
- The “Why”: যদি ইউজার ফর্মে সব ডাটা ঠিকঠাক দেয়, তবে Controller প্রথমে সার্ভিস লেয়ারকে কল করে ডাটা সেভ করে, এরপর
Indexপেজে রিডাইরেক্ট করে দেয় (return RedirectToAction("Index"))।
💻 Code Implementation:
[Fact]
public async Task Create_IfNoModelErrors_ToReturnRedirectToIndex()
{
// Arrange: Mock setup...
PersonAddRequest request = _fixture.Create<PersonAddRequest>();
// এখানে ModelState এ কোনো এরর অ্যাড করা হলো না (অটোমেটিক্যালি IsValid = true হবে)
// Act
IActionResult result = await _personsController.Create(request);
// Assert: চেক করা যে এটি RedirectToActionResult ফেরত দিয়েছে কিনা
RedirectToActionResult redirectResult = Assert.IsType<RedirectToActionResult>(result);
// চেক করা যে ঠিক কোন মেথডে রিডাইরেক্ট হয়েছে
redirectResult.ActionName.Should().Be("Index");
}
৩. The ActionMethod Overloading Mystery [Importance: 8/10]
- The Question: Controller-এ তো
Createনামে দুটি মেথড আছে (একটি GET, একটি POST)। আমরা যখন_personsController.Create(request)লিখি, তখন সে কীভাবে বোঝে যে POST মেথডটিকে কল করতে হবে? - The Answer: Method Overloading-এর কারণে। GET মেথডের কোনো প্যারামিটার নেই, কিন্তু POST মেথডটি প্যারামিটার হিসেবে
PersonAddRequestরিসিভ করে। যেহেতু আমরা টেস্টে আর্গুমেন্ট পাস করছি, C# কম্পাইলার নিজে থেকেই POST ভার্সনটিকে কল করবে।
🚀 Modern .NET Architecture Pro Tips
হাসিব, Controller টেস্টিং নিয়ে লেকচারার ভিডিওর শেষে যে কথাটি বলেছেন তা খুবই ইম্পরট্যান্ট।
Controller-এর ভেতরে মূলত Routing, Model Binding, Validation এবং Authorization এর কাজ থাকে। কিন্তু আমরা যখন এইভাবে Unit Test লিখি (সরাসরি _personsController.Create() কল করে), তখন এই ৪টি জিনিসের কোনোটিই টেস্ট হয় না! কারণ আমরা সরাসরি C# মেথড কল করছি, HTTP রিকোয়েস্ট পাঠাচ্ছি না।
এ কারণেই ইন্ডাস্ট্রিতে Controller-এর জন্য Unit Test এর চেয়ে Integration Test বেশি প্রেফার করা হয়। Integration Test-এ আমরা একটি ফেক ব্রাউজার বা HttpClient দিয়ে আসল POST /persons/create রিকোয়েস্ট পাঠাই, যা Controller-এর সব লেয়ারকে টেস্ট করে।
খুব সম্ভবত এই কোর্সের পরবর্তী লেকচারেই Integration Testing শুরু হতে যাচ্ছে, যা তোমার “Chatrabash” প্রজেক্টের API টেস্টিংয়ের জন্য জাস্ট গেম-চেঞ্জার হবে! তুমি রেডি হলে সেই ট্রান্সক্রিপ্টটি দিতে পারো।