Skip to content

Latest commit

 

History

History
129 lines (78 loc) · 14.3 KB

File metadata and controls

129 lines (78 loc) · 14.3 KB

خلاصه دوره: Writing Highly Maintainable Unit Tests

  • پلتفرم: Pluralsight
  • مدرس: Zoran Horvat
  • امتیاز: ‎4.7/5
  • تاریخ انتشار: ‎March 2017
  • مدت‌زمان: ‎6h 15m
  • لینک دوره: Writing Highly Maintainable Unit Tests

این سند، نکات کلیدی دوره را خلاصه می‌کند. اگر فرصت داشتی، دیدن خود دوره خیلی مفیدتر است.

AI-Powered buttons

Teach Me: 5 Years Old | Beginner | Intermediate | Advanced | (reset auto redirect)

Learn Differently: Analogy | Storytelling | Cheatsheet | Mindmap | Flashcards | Practical Projects | Code Examples | Common Mistakes

Check Understanding: Generate Quiz | Interview Me | Refactor Challenge | Assessment Rubric | Next Steps

۱. چرا unit testها غیرقابل‌نگه‌داری می‌شوند و چطور جلویش را بگیریم

خلاصه: زُران اول از همه از دردسرهای ۱۵+ ساله‌اش با test suiteهای بزرگ و شکننده می‌گوید. قول اصلی دوره این است که یاد بگیری چطور testهایی بنویسی که با هر refactor کوچک در کد اصلی نشکنند، چطور تقریباً تمام duplication را از تست‌ها حذف کنی و چطور utilityهای تست‌نویسیِ قابل‌استفاده‌مجدد بسازی که سال‌ها دوام بیاورند.

مثال: یک تابع ساده‌ی «پیدا کردن بزرگ‌ترین عدد در آرایه» که ظاهراً درست کار می‌کند ولی برای حالت‌هایی مثل آرایه‌ی خالی یا null باگ‌های ریزی دارد — از آن مدل کدی که چند تست سطحی را پاس می‌کند ولی در production می‌ترکد.

لینک برای جزئیات بیشتر: Ask AI: Why unit tests become fragile

۲. اثبات صوری در برابر تست‌ کردن دنیای واقعی

خلاصه: زُران قدم‌به‌قدم نشان می‌دهد چطور می‌شود برای یک تابع خیلی کوچکِ پیدا کردن maximum، با استفاده از loop invariant و استقرا، اثبات صوریِ درستی انجام داد. این کار برای ۱۰ خط کد خیلی شیک است، اما در مقیاس‌های بزرگ عملاً غیرممکن می‌شود — و همین دلیل است که ما به تست‌ها نیاز داریم. تست‌ها درستی را «اثبات» نمی‌کنند؛ فقط روی ورودی‌های انتخاب‌شده نشان می‌دهند. ولی اگر آن ورودی‌ها را هوشمندانه انتخاب کنی، اعتمادبه‌نفس خیلی خوبی به تو می‌دهند.

مثال: اثبات این‌که در هر iteration حلقه، مقدار max درست به‌روزرسانی می‌شود، و بعد نشان دادن این‌که همین کد روی آرایه‌ی خالی fail می‌شود مگر این‌که با assertion یا contract جلویش گرفته شود.

لینک برای جزئیات بیشتر: Ask AI: Formal proof of correctness in unit testing

۳. از manual testing تا automated tests و test runnerها

خلاصه: این بخش نشان می‌دهد چطور از حالت «برنامه را اجرا کن و دستی عدد وارد کن» به تست‌های خودکار واقعی برسی (الگوی Arrange-Act-Assert، اسم‌گذاری توصیفی برای تست‌ها). حتی یک test runner حدوداً ۷۰ خطی از صفر می‌سازد تا نشان بدهد ایده‌ی کلی چقدر ساده است و این‌که تست‌ها باید روی هر build اجرا شوند.

مثال: نوشتن اولین failing test برای MyArray.Maximum(), درست کردن bug، و سبز شدن تست — همان feedback loop فوری که همه از آن خوشمان می‌آید.

لینک برای جزئیات بیشتر: Ask AI: Building your own test runner

۴. ؜state-based testing در برابر interaction-based testing

خلاصه: سؤال همیشگی: آیا باید فقط state نهایی را چک کنیم (state-based)، یا این‌که بررسی کنیم چه متدی با چه پارامترهایی صدا زده شده (interaction-based / mocking)؟ state-based معمولاً مجبورمان می‌کند stateهای داخلی را expose کنیم؛ interaction-based encapsulation را حفظ می‌کند، ولی می‌تواند تست‌ها را شکننده و وابسته به implementation جزئی کند.

مثال: اضافه کردن «نقاط هدف» به یک آرایه — در state-based test، محتوای آرایه را بعد از عمل بررسی می‌کنی؛ در interaction-based test، بررسی می‌کنی که Append() دوبار با مقادیر ۳ و ۵ صدا زده شده است.

لینک برای جزئیات بیشتر: Ask AI: State vs interaction testing

۵. قابل‌تست کردنِ کد production (بدون خراب کردن design)

خلاصه: فقط برای خاطر تست، state داخلی را expose کردن در بلندمدت خطرناک است. زُران نشان می‌دهد چطور می‌شود از internal و attributeای مثل InternalsVisibleTo استفاده کرد، ولی در نهایت استدلال می‌کند که بعضی وقت‌ها بهتر است تعدادی عضو publicِ حساب‌شده داشته باشیم تا این‌که ترفندهای عجیب بزنیم. راه‌حل ریشه‌ای این است که از ابتدا کد را با دید تست‌پذیری طراحی کنیم.

مثال: اضافه کردن یک متد public مثل GetElementAt(int index) فقط به‌خاطر یک تست، و بعد از چند سال متوجه شدن این‌که اصلاً نباید public می‌بود.

لینک برای جزئیات بیشتر: Ask AI: Making code testable without exposing internals

۶. مدیریت dependencyها و mockingِ درست

خلاصه: بیشتر شکست‌ها و شکستن تست‌ها از مدیریت بد dependencyها می‌آیند. زُران اول mocking دستی را نشان می‌دهد، بعد سراغ Moq می‌رود؛ اما مهم‌تر از همه این است که چطور ساختار کد را طوری طراحی کنی که dependencyها قابل inject شدن باشند و تست‌ها فقط روی unit موردنظر تمرکز کنند.

مثال: تست کردن سرویسی که با یک repository صحبت می‌کند — repository را از طریق interface mock می‌کنی، فقط callهایی را که برای این تست مهم هستند verify می‌کنی و بقیه را نادیده می‌گیری.

لینک برای جزئیات بیشتر: Ask AI: Clean dependency management in unit tests

۷. ؜Abstract Data Typeها؛ برگ برنده‌ی اصلی

خلاصه: به‌جای این‌که کلاس‌های concrete را مستقیماً تست کنی، روی interfaceها یا abstract base classها تست بنویس. همین یک تغییر باعث می‌شود تست‌هایت زیر refactorهای بزرگ و بازنویسی‌های عمیق، زنده بمانند.

مثال: نوشتن تمام تست‌ها بر اساس IList<T> به‌جای MyList<T> — حالا می‌توانی پیاده‌سازی داخلی را کامل عوض کنی، بدون این‌که حتی یک تست بشکند.

لینک برای جزئیات بیشتر: Ask AI: Testing against abstract data types

۸. تست کردن generic typeها و interfaceها مثل یک حرفه‌ای

خلاصه: این بخش درباره‌ی generic constraintها، نکات covariance/contravariance و مخصوصاً روش تست کردن پیاده‌سازی‌های interfaceهاست به‌طوری‌که تست‌ها به هیچ کلاس concrete خاصی گره نخورند. این‌جاست که تست‌ها واقعاً bulletproof می‌شوند.

مثال: یک test suite استاندارد برای هر پیاده‌سازیِ IEquatable<T> که با کمک reflection بررسی می‌کند تمام اعضای لازم به‌شکل درست رفتار می‌کنند.

لینک برای جزئیات بیشتر: Ask AI: Testing generic types and interfaces

۹. کتابخانه‌های تستِ قابل‌استفاده‌مجدد و اصول طراحی تست

خلاصه: هر وقت لازم است یک رفتار پیچیده را بارها و بارها تست کنی (مثل equality درست، الگوی IDisposable، semantics نوع مقدار (value-type semantics) و …)، به‌جای copy-paste کردن، یک testing library کوچک بساز. زُران یک equality tester می‌سازد که ۲۹ قانون را چک می‌کند، درحالی‌که خود تست فقط ۶ خط است.

مثال: یک تست تک‌خطی که بررسی می‌کند یک struct مثل Date تمام ویژگی‌های لازم برای یک value type خوب را دارد: equality درست، hash code درست، operatorهای مناسب، sealed بودن در صورت نیاز و...

لینک برای جزئیات بیشتر: Ask AI: Building reusable testing libraries

۱۰. شرایط خطا و سناریوهای منفی (جایی که اکثر توسعه‌دهنده‌ها اشتباه می‌کنند)

خلاصه: پرتاب exception برای ورودی‌های نامعتبر، در خیلی از مواقع یک code smell است. بیشتر «خطاها» در واقع اشتباهِ caller هستند (bug در کدی که از ما استفاده می‌کند). زُران مفهوم Design by Contract را معرفی می‌کند — preconditionها، postconditionها و invariantها — و نشان می‌دهد که چطور contractها می‌توانند جای ده‌ها unit test را بگیرند.

مثال: یک interface برای repository که contractهای صریح دارد → حالا می‌توانی حدود ۳۰٪ از unit testها را حذف کنی، چون همان قواعد توسط contractها در هر اجرای واقعی چک می‌شوند.

لینک برای جزئیات بیشتر: Ask AI: Design by Contract in unit testing


درباره‌ی خلاصه‌کننده

من Ali Sol هستم، یک Backend Developer. برای آشنایی بیشتر: