هنر ظریف تست نویسی، TDD را بشناسیم و در دام های آن نیافتیم!

هنر ظریف تست نویسی، TDD را بشناسیم و در دام های آن نیافتیم!

دانستن اینکه چه وقت و چگونه از این تکنیک گاها بحث برانگیز (اما مفید) استفاده کنیم، کلیدی ست.

امروزه، جدل در مورد تست نویسی به پایان رسیده است: تست نویسی برای محصولات واقعی یک امر ضروری است. از این گذشته، تست نویسی این اطمینان را به شما می دهد که در حال ساختن نرم افزار پایداری هستید که یا خودتان بعدا قرار است با آن کار کنید یا مهندس دیگری قرار است آن را بهبود دهد.

TDD Test Driven Development (كه كنت بك در اواخر دهه 1990 دوباره آن را كشف كرد) از جنبش برنامه ريزي افراطي (extreme programming) ظهور کرد و مهندسان را به همكاري تشويق كرد. TDD (قانون "قرمز، سبز، ریفکتور") حکم می کند که توسعه دهندگان ابتدا باید تست بنویسند و بعد کد آن را بنویسند. در روزهای اوج تست TDD، به جای آنکه به عنوان یکی از روش های تست با آن رفتار کنند، اغلب به عنوان تنها روش تست با آن رفتار می کردند (در واقع ، محبوبیت همه یا هیچ در نهایت باعث انصراف برخی افراد در استفاده از آن شد.).

TDD ابزاری فوق العاده مفید است، خصوصاً اگر مورد به مورد استفاده شود.

اولین کسی باشید که به این سؤال پاسخ می‌دهید

من اغلب، وقتی فیچر جدیدی را به یک محصول اضافه می کنم یا متوجه وجود یک باگ می شوم ، به جریان TDD می پردازم. اگر مشخص نباشد که چگونه باید حل این مسئله را شروع کنم، بهترین راه برای من تست است. تست نویسی من را مجبور می کند مسئله را به مراحل مختلف تقسیم کنم تا به یک راه حل اولیه دست پیدا کنم، و در مراحل بعد با ریفکتور کردن به یک راه حل تمیزتر برسم.

در TDD ، شما اساساً این سه مرحله را تکرار می کنید:

مرحله 1: قرمز (نوشتن یک تست)

به رفتاری که می خواهید کد شما داشته باشد فکر کنید. اگر این رفتار چندین قسمت دارد، آن را به مراحل کوچکتر تقسیم کنید. هر مرحله نیاز به تست خاص خود دارد (در صورت لزوم آنها را لیست کنید.). سپس برای هر رفتار جداگانه که اضافه کرده اید، یک تست بنویسید. تست ها را اجرا کنید و مشاهده کنید که مطابق انتظار Fail می شوند. اگر تستی مطابق انتظار Fail نشد، آن را دیباگ کنید.

مرحله 2: سبز (Pass کردن تست)

هنگامی که یک تست مطابق انتظار Fail شد، چند کد کاربردی بنویسید تا Pass شود. طراحی یا پرفورمنس کد در این مرحله مهم نیست، اما بعداً مهم خواهد بود. تست مربوطه را اجرا کنید تا Pass شدن آن را دریافت کنید، سپس همه تست های موجود در آن فایل را انجام دهید تا مطمئن شوید که همگی Pass میشوند. در صورت Fail شدن تست مربوطه، به آخرین نسخه کدی که قبلاً Pass شده است برگردید. آن تست را کوچکتر کنید، سپس چرخه را دوباره شروع کنید.

مرحله 3: ریفکتور

اکنون که از همه تست های خود چراغ سبز دریافت کرده اید، می توانید با اطمینان کد خود را ریفکتور کنید.
به دنبال بهبود تست های خود باشید، مانند توصیفی بودن و واضح بودن نام متغیرها و یا جدا کردن منطق پیچیده از یک متد. پس از هر تغییر، تست ها را انجام دهید تا مطمئن شوید همه چیز هنوز Pass می شود. به یاد داشته باشید که ریفکتورینگ به معنای بهتر کردن طراحی کد است، نه تغییر رفتار آن. افزودن رفتار جدید منجر به Fail شدن تست می شود، بنابراین بهتر است به جای پیش بینی نیازهای آینده سیستم ، بر روی رفتار موجود تمرکز کنید.
وقتی ویژگی جدیدی اضافه کردید، چرخه ی TDD را مجددا تکرار کنید. این فرآیند ممکن است در ابتدا طولانی باشد، اما با تمرین بیشتر، زمانی که در هر مرحله صرف میکنید، کاهش می یابد.

مهارت TDD

ممکن است به سادگی در اصول TDD گم شوید. من خودم تحت فشار این روند قرار گرفته ام. در اوایل کارم، بیش از حد تست نویسی کردم. تست هایی نوشتم که درگیر تست کتابخانه شخص ثالث (third-party library) می شد و یا تست های کافی درمورد منطق تجاری (Business Logic) برنامه نمی نوشتم. همچنین دیده ام که برخی با تست نوشتن باعث آسیب به طراحی برنامه می شوند، زیرا بیش از حد تلاش می کنند که قسمت های برنامه را برای تست جدا کنند، درنتیجه ریفکتورینگ برنامه را دشوارتر می کنند.

بله، ممکن است بیش از حد تست نویسی کنید! به ویژه اگر از این اصل TDD پیروی کنید که: "بدون Fail کردن تست، حتی یک خط کد هم ننویسید". با توجه به این قانون شما باید برای هر خط کدی که مینویسید، یک تست داشته باشید و نتیجه ی آن تست های بی معنی ای می باشد که نگهداری آنها با گذشت زمان دشوار می شود.

علاوه بر این اگر تست ها سریع نباشند، بیش از آنکه مفید واقع شوند، دست و پا گیر می شوند. خودتان را به اجرای همزمان بخشی از کدها محدود کنید تا سریع تر پیش بروید.

اما کدام یک را اجرا کنید و چند مرتبه؟ اینجاست که هنر تست نویسی وارد عمل می شود.

هنر TDD

به عنوان یک قاعده کلی، کد باید قبل از ارسال برای بازبینی و راه اندازی محصول، تست شود. اگرچه نحوه شروع تست نویسی برای هر برنامه نویس متفاوت است، اما معمولاً با یک تست واحد (unit test) شروع می شود که واحدهای جداگانه مانند کلاس ها ، ماژول ها و توابع را به صورت جداگانه آزمایش می کند.

وقتی برای یک درخواست وب یا کلاسی که با کلاس دیگر رابطه دارد تست می نویسید، یک تست یکپارچه ‌سازی (integration test) ایجاد می کنید که نحوه کار واحدهای جداگانه را با هم آزمایش می کند.

بسته به تیم مهندسی شما، ممکن است تست های سیستمی (system tests) نیز داشته باشید که عملیاتی بودن برنامه از دید کاربر و همچنین پرفورمنس و لود برنامه را آزمایش می کند.

یا تست پذیرش (acceptance tests) که قابل استفاده بودن یک محصول را با توجه به نیازمندی های تجاری آزمایش میکند.

با توجه به تجربه من، بیشتر افراد نوشتن تست و دیدن مقادیر آن را دوست دارند، اما در می یابند که تکرار یک تست و همچنین سرعت آن تعیین می کند که آیا آن را اجرا می کنند یا نه.

سرعت

TDD لزوما کند نیست. تست هایی را که اجرا می کنید فقط به کدهایی که در حین توسعه می نویسید، محدود کنید. اگر یک تست نسبتا بزرگ دارید، برای اجرای آن از یک سرور یکپارچه ساز مانند CircleCI استفاده کنید، چه با push کردن کامیت های کوچک چه با push کردن کل برنچ پس از انجام کل تسک.

با توجه به هرم تست (که اولین بار توسط Mike Cohn در کتاب Succeeding with Agile ارائه و توسط Martin Fowler مشهور شد)، اکثر تست ها باید unit test باشند؛ با ورودی های کم و معمولا یک خروجی واحد. این تکنیک تضمین می کند که برنامه شما با توسعه یافتن، منعطف خواهد ماند و این اطمینان را می دهد که با تغییر کد نیازی نیست که تعداد زیادی از تست ها را تغییر دهید.

 هنر ظریف تست نویسی، TDD را بشناسیم و در دام های آن نیافتیم!

Over-testing (تست نویسی بیش از حد)

توجه داشته باشید تستی که می نویسید برای برنامه شما منحصر به فرد باشد. اگر چندین تست برای یک چیز دارید، باید تست هایتان را در هم ادغام کنید. اگر بیشتر از زمان نوشتن یا ریفکتور کردن کد، زمان خود را صرف تغییر تست می کنید، احتمالا بیش از حد تست مینویسید (over-testing). از دور انداختن تست ها نترسید. علاوه بر این هنگام استفاده از ابزارهای تست از معیارهای پوچ پرهیز کنید. ممکن است به سادگی در معیارهایی مانند test coverage و سرعت گرفتار شوید ولی نیازی نیست آنها را به 100 درصد برسانید. در عوض مطمئن شوید که برنامه ی شما دارای تست های کافی high-level (سطح بالا) و تعداد زیادی تست های واحد (unit test) برای کامپوننت های مختلف مثل کلاسها، ماژولها و غیره میباشد.

TDD برای تیم

این باور را ایجاد کنید که تست نویسی (و TDD) برای تیم تان با ارزش است و بنابراین اعضای تیم این تکنیک را در کار خود می گنجانند. TDD می تواند تیم شما را در مورد کدی که در حال تولید آن هستند مطمئن تر کند و موجب انعطاف پذیری بیشتر برنامه شود.

به طور کلی TDD مکانیزمی را برای دریافت سریع فیدبک فراهم می کند و منجر به طراحی بهتر نرم افزار از طریق ریفکتور کردن می شود. علاوه بر این، هم تیمی ها را برای برطرف کردن مشکلات و یافتن راه حل های قابل تست تشویق میکند. اگر هم تیمی هایتان به تازگی با TDD آشنا شده اند، به آنها فرصت دهید تا خود را با آن وفق دهند و تشویقشان کنید که بهترین روش را پیدا کنند. با کمک TDD، تیم ها از کدهایی که بهتر طراحی شده اند و مستندات واضح تری در حین توسعه ی نرم افراز بهره مند می شوند و می توانند بدون ایجاد خللی در کدهای قبلی ، قابلیت جدیدی به آن اضافه کنند.

منبع