تست‌های دروغ‌گو!

مقدمهشما هم احتمالا در فرآیند برنامه‌نویسی به این مشکل خورده‌اید که بعد از انجام تغییراتی در کد و اجرای تست‌ها، در برخی موارد با نتایج ناموفقی روبرو می‌شوید که ارتباطی به تغییرات کد شما نداشته و در صورت تکرار اجرای آن‌ها، به طرز عجیبی مشکلی دیده نخواهد شد. در متن پیش رو، به بررسی تست‌های Flaky می‌پردازیم.به چه تستی Flaky می‌گوییم؟به طور خلاصه به هر تستی که برای یک کد یکسان، می‌تواند هم نتیجه‌ی «موفق» و هم نتیجه‌ی «ناموفق» در پی داشته باشد، تست Flaky می‌گوییم. این تست‌ها در صورت ناموفق شدن، با اجرای دوباره یا چندباره بالاخره موفق خواهند شد.چه مشکلاتی را به وجود می‌آورد؟این تست‌ها علاوه بر آزاردهنده بودن، هزینه‌بر و زمان‌بر نیز هستند. سناریو زیر را در نظر بگیرید:توسعه‌دهنده‌ای در روز چندین بار کد خود را push کرده و منتظر نتایج تست از سمت سیستم CI می‌ماند. سیستم CI بعد از دقایقی چند مورد تست با اجرای ناموفق را گزارش می‌دهد. توسعه‌دهنده مجبور می‌شود که تست‌ها را یکی یکی بررسی کرده تا از عدم وجود مشکل در کد خود مطمئن شود. اگر پس از بررسی متوجه شد که مشکل از کدش نبوده یا حتی از قبل می‌دانست که این تست‌ها Flaky هستند، سعی می‌کند دوباره تست‌ها را اجرا کند تا زمانی که اجرای موفقی داشته باشند.این تست‌ها باعث می‌شوند فرآیند CI دیگر مطمئن نباشد. در هربار اجرای ناموفق CI، فرد مسئول نمی‌داند الان باید دوباره تست را اجرا کند یا نسبت به آن بی‌توجه باشد. این بی‌توجهی اثرات مخرب دیگری دارد که ممکن است رغبت توسعه‌دهندگان به نوشتن و اجرای تست را کاهش دهد.با اجرای دوباره یا چندباره این تست‌ها، زمان اجرای پایپلاین افزایش یافته و باعث اتلاف وقت و انرژی توسعه‌دهندگان می‌شود. با زیاد شدن زمان Commit Stage که زمان توصیه شده برای نگه‌داشت آن زیر ۱۰ دقیقه است، ممکن است توسعه‌دهنده روی کار دیگری متمرکز شده که این تغییر کار و پرش، خود هزینه‌زا خواهد بود.همچنین باعث می‌شوند تا اجرای پایپلاین شاخه‌ی master مخزن کد با مشکل مواجه شده و آدم‌های زیادی را به خود مشغول کند. بعد از چند بار رخ دادن این موضوع نیز ممکن است افراد به این هشدارها بی‌توجهی کرده و این بی‌توجهی به تست‌های مشکل‌دار بررسی نشده، محیط عملیاتی را هم دچار مشکل کند.بعضی برای خلاص شدن، این تست‌ها را به صورت موقت یا دائمی غیرفعال می‌کنند که احتمالا این کار نیز موجب بروز اشکالاتی در محیط عملیاتی خواهد شد.شرکت بزرگی مثل گوگل نیز از این قاعده مستثنی نبوده و می‌گوید ۱.۵ درصد از تست‌های تولید شده توسط توسعه‌دهندگان، Flaky است. این حالت برای یک پروژه معمولی گوگل که ۱۰۰۰ تست دارد، باعث می‌شود تا اجرای حدود ۱۵ تست به اشتباه ناموفق اعلام شود. بررسی هرباره‌ی ۱۵ تست کار پرهزینه‌ای بوده که معمولا توسعه‌دهندگان با توجه به تاریخچه‌ی اعلام غلط نتایج ‌تست‌ها، تصمیم ‌می‌گیرند به آن توجهی نکنند.منشا تست‌های Flaky چیست؟موارد مختلفی وجود دارد که ممکن است باعث شود تست‌ها Flaky شوند و با هربار اجرا روی یک کد یکسان، نتایج متفاوتی به دست آید. در زیر، به بعضی از این موارد اشاره شده است:هم‌روندی (Concurrency)در تست‌های بزرگ (Integration Test) ممکن است کامپوننت‌ها و Threadهای موازی تاثیر‌گذار باشند. اگر در محیط عملیاتی یا شبه‌عملیاتی مشغول تست هستید، ممکن است دیگر درخواست‌های خارج از محدوده‌ی تست نیز تاثیرگذار باشند. همچنین ممکن است اجرای تست‌ها به صورت موازی روی هم اثر بگذارند.ایزوله‌ی ناکافی محیط (Insufficient Isolation)منابع مشترک در بین تست‌ها مانند دیتابیس، صف، فایل و ... ممکن است باعث شود تا این تست‌ها با مشکل مواجه شوند. دقت کنید این اشتراکات روی هم تاثیرگذار نباشند و یا اگر تاثیر‌گذار هستند به صورت همزمان اجرا نشوند.وابستگی به ترتیب اجرا (Test Order Dependency)یکی از حالت‌های مشکل قبل، وابستگی یک تست به محیط تست اجرا شده‌ی پیشین خود است. با اجرای تست‌ها با ترتیبی تصادفی، این تست‌ها را می‌توان شناسایی کرد.آماده کردن و پاکسازی محیط (Test Setup & Tear Down)این ایراد نیز از حالت‌های محیط با ایزوله‌ی ناکافی ‌است. محیط اجرای تستِ خوب باید قبل و بعد از اجرای تست یکسان باشد. دقت کنید بعد از اجرای هر تست، منابع استفاده شده را پاکسازی و به حالت قبل برگردانید. مثلا برای تست نیازمند به دیتابیس، میتوان عملیات را در یک transaction انجام داد تا بعد از اجرا به راحتی پاکسازی شود.زمان (Time)بعضی اوقات timeoutهایی که در این نوع تست‌ها برای یک درخواست استفاده می‌کنیم، کافی نیستند. بعضی اوقات با تغییر timezone محیط تست، این مشکل به وجود می‌آید. بعضی اوقات ممکن است در ساعت خاصی از شب یا در ساعت تغییر زمان تابستانه این اتفاق بیفتد. بهتر است شرایط زمانی محیط تست خود را ثابت کرده تا بسته به شرایط مختلف، تست‌های متفاوت و دقیق‌تری داشته باشید.استفاده از منابع خارجی (3rd Party Systems)استفاده از منابع خارجی به دلایل مختلفی مانند قطعی یا سرعت پایین شبکه، ناپایداری خود منبع و ... ممکن است باعث اجرای ناموفق شود. در تست‌های کوچک باید از راه‌حل‌های جایگزین قابل‌اتکاتری مثل mock استفاده کرد. البته استفاده از سیستم‌های واقعی در برخی از آزمون‌ها غیر قابل اجتناب است.تصادفی بودن ورودی (Random Inputs)در تست‌هایی با ورودی‌ تصادفی (Fuzz Testing)، این احتمال همیشه وجود دارد که اجرای تست ناموفق باشد. نتایج این نوع تست‌ها به خودی خود درست و قابل اتکا بوده و در صورت مشکل باید آن را به طور کامل بررسی کرد. نکته مهم این است که با اجرای دوباره‌ی تست ناموفق، نباید از ورودی جدیدی استفاده شود و همچنان باید این تست ناموفق تلقی شود تا بعدا، آن ورودی بررسی و مشکل حل شود.در مواجهه با تست‌های Flaky چه کنیم؟بدیهی‌ترین راه‌حل که به ذهن می‌رسد اجرای اتوماتیک دوباره‌ی تست است تا مطمئن شویم اجرای قبلی اتفاقی نبوده. گوگل نیز از همین روش استفاده کرده و هر تست که با اجرای ناموفق مواجه شود را تا ۳ بار دیگر اجرا می‌کند. این روش با درصد خطای کمی که دارد مورد قبول بوده و سطح اطمینان از نتایج تست‌ را بالا برده است.هر موردی را که به عنوان تست Flaky شناسایی شد، باید در جایی مناسب و مشترک بین توسعه دهنده‌ها مکتوب کنیم تا بقیه افراد نیز تا رفع مشکل، از آن آگاه باشند. این کار علاوه بر این که باعث می‌شود تا بقیه توسعه‌دهنده‌ها در صورت برخورد با این تست زمان کم‌تری مصرف کنند، باعث می‌شود حس اطمینان نسبت به نتایج اجرای بقیه تست‌ها باقی بماند. این فرایند می‌تواند دستی یا به صورت اتوماتیک باشد. بهتر است فردی به طور خاص این نتایج را تحلیل و به توسعه‌دهندگان مربوطه برای رفع مشکل تست اطلاع دهد.سخن پایانیبه طور کلی تست‌های Flaky موضوعی نیست که بتوان آن‌را یکبار برای همیشه حل نمود. این چالش برای شرکت‌های بزرگ تا کوچک به طور مستمر وجود دارد و سعی می‌شود تا با روش‌هایی، اثرات آن را به حداقل رساند.منابع برای مطالعهدر نوشتن این متن بعضی از منابع زیر کمک‌کننده بود. اگه دوست داشتید اطلاعات بیش‌تری کسب کنید، میتوانید به آن‌ها سری بزنید.Developer Productivity EngineeringFlaky Tests at Google and How We Mitigate ThemFlaky Tests - A War that Never EndsHow to Deal With and Eliminate Flaky TestsEradicating Non-Determinism in TestsQuarantine: Flaky Test Detector Toolمعضل تست‌های متزلزلشما هم اگه تجربه‌ای در مواجه با این تست‌ها دارید، خوشحال میشم راه‌حلتون رو به اشتراک بگذارید.