פתרונות וטיפים לטיפול יעיל ב- Flaky Tests

איתי אגמון, CTO ב-Top-Q

flaky testsבדיקות לא-יציבות בתחום אוטומציה של בדיקות תוכנה, אינן רק חסרות תועלת, אלא גם מסכנות את אמינות מערך הבדיקות האוטומטיות כולו. אפילו החברות הגדולות בתעשייה חוות Flaky Tests, וכך תתמודדו איתם גם אתם.

לא אחת קורה שמריצים טסטים, אך הם לא יציבים וחד-משמעיים. הטסטים הללו זכו לשם Flaky Tests, מינוח שהשתרש בעולם האוטומציה ובדיקות התוכנה כדי לתאר חוסר יציבות של בדיקות אוטומטיות. אלו הן בדיקות שהתוצאה שלהן היא לא חד-משמעית, כלומר שהן מסתיימות ללא שינוי בקוד או בדאטה, אך פעם הן עוברות, ופעם לא. אם אותה בדיקה באותם התנאים פעם אחת עברה ופעם אחרת נכשלה – הבדיקה היא Flaky.
ניתן להיתקל ב- Flaky Tests בכל השכבות של מודל פירמידת הבדיקות הפונקציונליות של מרטין פאולר, ובמיוחד בבדיקות End-to-End  ובבדיקות GUI.

מה הבעיה עם Flaky Tests?
טסטים שהם לא דטרמיניסטים סובלים משתי בעיות מרכזיות: ראשית, הם חסרי תועלת כי תוצאת הבדיקה לא ברורה והם לא נותנים מידע אמין לגבי הקוד המסוים שנבדק. שנית, טסטים כאלה גם מהווים מעין 'זיהום ויראלי' לכל מערכת הבדיקות. הרציונל שעומד מאחורי הסיבה הזו, הוא שנוצר אפקט שמשפיע לרעה על הסביבה כולה: אם נשחרר טסט Flaky, הוא ישתרש ויגרור אנשים נוספים לייצר טסטים כאלה. זאת ועוד, הם גם מסתירים באגים אמיתיים וכאשר נתרגל לקבל הרבה אזעקות שווא על Flaky Tests, בסופו של דבר נתעלם מהן וכך נפספס התראות על תקלות אמיתיות. כאשר Flaky Tests מתרבים והופכים ליותר בולטים, הם יכולים להביא לזלזול בבדיקות, ומכאן ועד לכישלון של פרויקט האוטומציה – הדרך קצרה.

הסיבות ל- Flaky Tests
flaky tests reasons

מדוע מלכתחילה ישנם טסטים שמתנהגים בחוסר יציבות? ישנן סיבות רבות הגורמות לתופעה, אך בין הסיבות השכיחות יותר ניתן למצוא:

  1. Sleep – המתנה "טיפשה": פעמים רבות כאשר משהו לא עובד במערכת הנבדקת, מוסיפים המתנה שלאחריה הכול נפתר ועובד לפתע כמו קסם. אבל העובדה שההמתנה עבדה במקרה זה, לא אומרת שהיא תעבוד בכל מקרה. אם במערכת אחרת בסביבה אחרת תהיה אפילו חריגה קטנה מזמן ההמתנה שהוגדר – יתחילו נפילות.
  2. תלות בין טסטים: טסטים שלא דואגים "לנקות" אחריהם וטסטים התלויים ב- Entities שנוצרו בטסט קודם יפריעו לטסטים הבאים לעבור. גישות עבודה אלה מאפשרות לטסטים לשנות את הסביבה ולהרוס אותה.
  3. באגים בכלים בהם אנו משתמשים: אפילו בכלים וספריות כדוגמת סלניום ואפיום יכולים להיות באגים שעלולים לגרום לקריסות והתנהגויות שאינן תמיד צפויות. קריסות  של גריד או סרברים קטנים יביאו איתן נפילה בנקודה לא קבועה במהלך ההרצה של הטסט וייצרו חוסר דטרמיניסטיות.
  4. מערכת צד שלישי: התחברות למערכת חיצונית (מערכת CRM, לדוגמה) שקורסת ומשפיעה על הטסט.
  5. מקביליות: כאשר רוצים לחסוך זמן ומכניסים מקביליות לתוך האוטומציה לטובת ריבוי משימות, יש להשתמש במנגנוני נעילה, סנכרון ותיאום בין התהליכונים (Thread Safety). כאשר לא עושים זאת נכון נוצרות שגיאות Race Condition שישפיעו על ההרצה. בעיות במקביליות לא חייבות להיות בתכנות האוטומציה, אלא יכולות להיווצר גם בסביבה הנבדקת או באופן שבו בודקים אותה.
  6. הסתמכות על מערכת לא יציבה: סטים נכשלים כאשר מסתמכים על אזור במערכת שאינו דטרמיניסטי, כמו מערכת לומדת, או שהמערכת הנבדקת עצמה אינה יציבה.

פתרון 1: Rerun – טסט חוזר
אפילו לענקי התעשייה כמו גוגל יש Flaky Tests, והם מדווחים שאחוז וחצי מתוצאות כל ההרצות שלהם הם כאלה. ל- 16% מהבדיקות שהם מריצים יש מרכיב כלשהו שהוא Flaky, מה שאומר שמומחי אוטומציה צריכים להשקיע זמן ולחקור אותם כדי להוציא טסטים ללא פגם. זהו משאב יקר שהולך לאיבוד, ובגוגל מתארים זאת כבעיה מאוד כואבת. אז מה עושים? Rerun של הטסטים.

return - flaky test articleRerun הוא הפתרון האינטואיטיבי הראשוני שפונים אליו. בין אם עובדים עם TestNG או JUnit עם git, Maven ו- Jenkins, בכל הפלטפורמות ניתן להשתמש בממשקים, פלאגינים ופיצ'רים המאפשרים להגדיר מתי רוצים לחזור על טסט ומתי לא, וכמה פעמים לחזור עליו במידה והוא נכשל לפני שמחליטים שהוא נכשל באופן סופי. בסיום ההרצה נוצרת רשימה של כל הטסטים שנכשלו, כך שניתן להריץ אותם מחדש. חלקם אף מספקים מידע שיכול לאפשר לזהות מתי החל ה- Flakiness.

אבל לפעולת ה- Retry יש גם חסרונות:
1. היא אורכת הרבה זמן
2. היא מאפשרת למהנדסי האוטומציה להרשות לעצמם לעבוד בצורה פחות מדויקת מתוך הנחה שמנגנון ה- Retry יטפל בחוסר יציבות.

פתרון שמאוד עוזר בצמצום Flakiness הוא הרצה של כל טסט אחרי הפיתוח שלו ולפני הכנסתו לסוויטה המרכזית. זו דרך נוספת להתייחס ל- Rerun, ולפיה אחרי מימוש טסט מומלץ להריץ אותו מספר רב של פעמים לפני שמחליטים שהוא ראוי להיכנס לסוויטה.

פתרון 2: Test Quarantine – בידוד טסטים
טכניקת הבידוד פותרת את החסרונות של ה- Rerun, ומציעה לבודד טסטים לא יציבים, במקום להריץ אותם או להשאירם בתוך המערכת. כפי שמשתמע מהשם, את הטסט הלא-יציב יש להוציא מהסוויטה ולשים ב"הסגר". ניתן לייצר קבוצה ולשייך אליה את כל הטסטים שהם לא יציבים ובכל ההרצות לעשות Exclude לקבוצה זו, כך שהיא לא תשפיע על תוצאות הטסטים.

איך מזהים Flaky Tests? אחד המאפיינים של הטסטים הלא-יציבים, כהגדרה, הוא החמקמקות שלהם וחוסר היכולת לדעת מי הם. על מנת לבודד אותם ולטפל בהם, צריך לגלות איזה טסטים הם באמת Flaky, ולא לסמוך על האינטואיציה כדי להגדיר מה יציב ומה לא. כדי לעשות זאת אוספים תוצאות של טסטים ומטא-דאטה ויוצרים מערכת למטרת ניתוח הנתונים על מנת לראות את ה- Flakiness באופן אמיתי ומדויק.

איסוף המידע המתאים לטובת תיקון: יצירת מערכת שיודעת לזהות איזה טסטים אינם יציבים ואולי אף להכניסם לבידוד באופן אוטומטי זה מצוין, אבל על אף הסיפוק שבקבלת סוויטה "ירוקה" ונקייה מטסטים כושלים – זה לא מספיק, מכיוון שעדיין ישנם טסטים שפשוט לא רצים.
אבל באיזשהו שלב יש צורך להוציא את אותם הטסטים מהבידוד, לחקור את סיבות הליבה לכך שהם Flaky ולהחזיר אותם לתוך הסוויטה המרכזית. כיצד נעשית החקירה? אוספים את כל המידע הרלוונטי שאפשר: צילומי מסך, Database Dumps, System Dumps, HTTP Dumps ו- Log Files (בהתאם למערכת ולתחום בו פועלים, כמובן), וחוקרים לעומק. חשוב לאסוף כל מידע שיכול להיות רלוונטי, גם אם לא לטסט הספציפי שנבדק.

סטטוס fail to verify: עוד ענק בתעשייה שחווה בעיות Flaky Tests הוא חברת Dropbox. החברה מעידה על עצמה שיש לה המון טסטים לא יציבים, וקצב הכניסה שלהם לבידוד כמעט זהה לקצב שמצליחים בחברה להוציא אותם מהבידוד. זאת ועוד, כ- 25% מהטסטים שהוחזרו לסוויטה מהבידוד – חזרו להיות Flaky, מאחר שלא הצליחו לזהות את הסיבה לחוסר היציבות שלהם. הפתרון שהגיעו אליו ב- Dropbox הוא טכניקת fail to verify test status, סטטוס חדש של טסטים שהוא פתרון משלים לבידוד.

לפי הטכניקה הזו לא מסתכלים על הטסט כאל מכלול שלא משנה היכן התגלתה בו אי-היציבות, אלא מבחינים בין טסט שנכשל בחלק הארי שלו (מה שרצינו לבדוק), לבין טסט שנכשל בשלב נלווה. כך, במקום להתעכב על התהליך כולו ולהכניס לבידוד טסט שמתנהג באופן לא-יציב בחלק שאינו רלוונטי לבדיקה, מזקקים את הטסט רק לחלק שמעניין אותנו ורואים האם הוא עבר או נכשל בחלק זה בלבד.

ב- Dropbox, לדוגמה, גילו שטסטים שהריצו על מחיקת קבוצות כשלו בכלל בחלק של הקמת הקבוצה, שלב לא-רלוונטי שהפיל את הבדיקה כולה. הפעולה המרכזית בטכניקה הזו היא מיון הטסטים, ובכך מצמצמים את מספר הטסטים שנכנסים לבידוד.

 

סיכום
Flaky Tests מתרחשים אצל כולם, אפילו אצל החברות הגדולות בתעשייה. הפתרון הראשון הוא לעשות Rerun שמאפשר להריץ מחדש כל טסט שנכשל בנפרד או לבצע הרצה של סוויטות שלמות, דוגמת קבוצת הטסטים שנכשלו. הפתרון השני הוא בידוד, שהוא חכם יותר ומתמודד עם החסרונות של ה- Rerun, אבל מצריך השקעה של ייצור מערכת שעוקבת אחרי התוצאות ודורשת לאסוף את המטא-דאטה כדי לאפשר לחקור את הבעיה. השלב הבא, שמומלץ לבצע לעיתים קרובות ולא לחכות עד שיצטברו עשרות טסטים כושלים, הוא החקירה ואיסוף המידע עבור התיקון כדי להבין את סיבות המפתח ל- Flakiness. ולבסוף – כדאי לשקול להוסיף את סטטוס ה- fail to verify, שעוזר לבצע הפרדה טובה בין טסטים עם מרכיבים לא יציבים, ולדחות את הכנסת הטסטים לבידוד.

כדי להתמודד טוב יותר עם Flaky Tests יש להבין שזו תופעה נפוצה שכדאי להטמיע במודעות כבעיה שצריך להתייחס אליה. מקמו אותה גבוה בסדר העדיפויות, תנו לה את המשאבים הדרושים והקצו זמן לעיצוב הטסטים וליצירה ותחזוקה של מערכות שעוזרות לזיהוי Flakiness, חקירה והוצאה מבידוד. בסיכומו של דבר, התופעה לא תיפתר מעצמה, הקדישו זמן לטיפול בה.

רוצים לשמוע עוד? דברו איתנו

מלאו פרטים ונחזור אליכם בהקדם