רבים מאיתנו חוו את זה. כתבנו test אוטומטי, דיבגנו (Debug), הכל עבד מצוין. הרצנו פעם אחת וזה עבר באופן חלק. אבל מתישהו, אולי אחרי כמה פעמים שהרצנו באופן ידני ואולי כשזה רץ באופן אוטומטי בתהליך CI/CD זה או אחר, הבדיקה פתאום נכשלת.
הנושא הזה מעייף וגורם לייאוש של עשרות בודקים ומפתחים.
הדבר שאנחנו מדברים עליו כאן נקרא Flaky Tests והוא נושא חם מאוד בעולם האוטומציה היום.
flaky tests או test flakiness הוא ביטוי המיצג חוסר יציבות של בדיקות אוטומטיות. אם אותה בדיקה באותם תנאים פעם אחת עברה ופעם אחרת נכשלה, הבדיקה היא flaky.
בעיני, 3 הצעדים הבאים הינם צעדים פשוטים ויכולים לקדם אותנו רבות לכיוון תרחישי אוטומציה יציבים יותר - בין אם בדרך ישירה או עקיפה.
על נושא הפחתת כמות בדיקות ה- E2E דיברנו גם בפירמידת הבדיקות במאמר הקודם אבל אין דרך להסביר עד כמה הנקודה הזו חשובה.
אנחנו חייבים לשים לב שאיננו בודקים באמצעות בדיקת E2E לוגיקה שיכולה להיבדק ברמה נמוכה יותר! (Unit tests/integration tests)
עיקרון single responsibility מדגיש ואומר לנו שכל רכיב תוכנה (פעולה/מחלקה) צריך לעשות דבר אחד ורק אחד ואותו עיקרון תקף גם כאשר אנחנו מדברים על בדיקות.
ככל שיהיו פחות שלבים ל- test שלנו, כך אמינותו תהיה נמוכה יותר! זה פשוט מאוד. מצד שני, כשאנחנו עושים יותר דברים, יש לנו יותר מקומות שאנחנו יכולים לטעות בהם.
ה-sleep הוא חבר טוב כמעט של כל מפתח אוטומציה בתחילת דרכו.
אנחנו כותבים תרחיש בדיקות, מריצים אותו בפעם הראשונה והוא עובר, מריצים אותו שוב ופתאום הוא נכשל.
מה קרה? לפעמים ישר אנחנו יכולים לראות את האזור הבעייתי ולפעמים אנחנו מגלים שאנחנו תלויים ברכיב אחר (שרת מסוים/Database/דף שיעלה בדפדפן וכו').
אם ה- test שלנו תלוי ברכיבים אחרים ובקבלת תשובה מהם, sleep הוא רעיון גרוע מאוד.
העניין בתלות ברכיבים שונים הוא שקצב חזרת התשובה מהם משתנה מאוד (בגלל שוני במערכת הפעלה/תוכנה/חומרה/דפדפן/מהירות אינטרנט וכו'). כך אף פעם לא נוכל באמת לדעת כמה אנחנו צריכים לחכות!
במקום המתנה של זמן מסוים, נרצה להמתין הפעם לתנאי מסוים. אם לדוגמה אנחנו מריצים אוטומציה עבור אפליקציית web, והמשך הריצה שלנו תלוי בהופעה של אלמנט מסוים בדף. אנחנו לא נחכה לפי זמן אלא נמתין עד הרגע שהאלמנט יופיע באמת.
במקרים רבים בהם נכתוב באמצעות כלי אוטומציה קיימים כמו selenium, נוכל להשתמש בפונקציות ה wait הקיימות.
במקרים אחרים פשוט נכתוב פעולה אשר תקבל תנאי, ותמתין עד שהוא יקרה. הפעולה תחזור אם התנאי הפך True או אם הזמן שהוקצב לפעולה נגמר.
כמו שכבר כתבתי בעבר, תרחישי בדיקה הם קוד, בקוד יש באגים, ובאגים צריך לתחקר. באמצעות לוג עבור כל פעולה שאנחנו מבצעים נוכל תמיד לתחקר את התקלות שלנו ולפתור אותן בקלות רבה יותר.
אני אוהב לכתוב לוג לפעולות שלי בדרך הבאה:
bool LoggedMethod(string str1, string str2)
{
log.info($"Started logged method with parameters - str1: {str1}, str2: {str2}")
bool returnValue = *method logic*
log.info($"LoggedMethod return value is: {returnValue}")
return returnValue
}
בפעולה הכתובה למעלה, במידה והיא עושה רק דבר אחד, אני מדפיס ללוג פעם אחת בתחילת הפעולה את שם הפעולה שאני מריץ ואת הפרמטרים שהתקבלו. בסוף הפעולה אני רושם ללוג את הערך שמוחזר מהפעולה רגע לפני החזרתו.
חשוב לזכור - אין דבר כזה יותר מדי לוגים! (כמובן שחשוב לסווגם)
לוגים הם אולי לא פתרון ישיר לייצוב האוטומציה שלנו, אך הם יכולים לתת לנו מידע רב לגבי הנפילות שלנו וכך נוכל להבין הרבה אודות כישלונות אקראיים.
כמובן שאת הלוגים חשוב מאוד לשמור לאורך זמן ורצוי גם לבצע מניפולציות על המידע שהצטבר בכדי להבין מגמות
אין ספק שקיימות דרכים רבות לייצוב תרחישי האוטומציה שלנו אז השתדלתי התמקד במספר פעולות פשוטות. הדרכים שציינתי מהירות לביצוע ועשויות להביא לשינוי גדול. ביצוע הבדיקות הנ"ל יקדם מאוד אותנו מאוד ביציבות התרחישים שלנו ויתרון רבות למערכת הבדיקות שלנו.
רבים מאיתנו חוו את זה. כתבנו test אוטומטי, דיבגנו (Debug), הכל עבד מצוין. הרצנו פעם אחת וזה עבר באופן חלק. אבל מתישהו, אולי אחרי כמה פעמים שהרצנו באופן ידני ואולי כשזה רץ באופן אוטומטי בתהליך CI/CD זה או אחר, הבדיקה פתאום נכשלת.
הנושא הזה מעייף וגורם לייאוש של עשרות בודקים ומפתחים.
הדבר שאנחנו מדברים עליו כאן נקרא Flaky Tests והוא נושא חם מאוד בעולם האוטומציה היום.
flaky tests או test flakiness הוא ביטוי המיצג חוסר יציבות של בדיקות אוטומטיות. אם אותה בדיקה באותם תנאים פעם אחת עברה ופעם אחרת נכשלה, הבדיקה היא flaky.
בעיני, 3 הצעדים הבאים הינם צעדים פשוטים ויכולים לקדם אותנו רבות לכיוון תרחישי אוטומציה יציבים יותר - בין אם בדרך ישירה או עקיפה.
על נושא הפחתת כמות בדיקות ה- E2E דיברנו גם בפירמידת הבדיקות במאמר הקודם אבל אין דרך להסביר עד כמה הנקודה הזו חשובה.
אנחנו חייבים לשים לב שאיננו בודקים באמצעות בדיקת E2E לוגיקה שיכולה להיבדק ברמה נמוכה יותר! (Unit tests/integration tests)
עיקרון single responsibility מדגיש ואומר לנו שכל רכיב תוכנה (פעולה/מחלקה) צריך לעשות דבר אחד ורק אחד ואותו עיקרון תקף גם כאשר אנחנו מדברים על בדיקות.
ככל שיהיו פחות שלבים ל- test שלנו, כך אמינותו תהיה נמוכה יותר! זה פשוט מאוד. מצד שני, כשאנחנו עושים יותר דברים, יש לנו יותר מקומות שאנחנו יכולים לטעות בהם.
ה-sleep הוא חבר טוב כמעט של כל מפתח אוטומציה בתחילת דרכו.
אנחנו כותבים תרחיש בדיקות, מריצים אותו בפעם הראשונה והוא עובר, מריצים אותו שוב ופתאום הוא נכשל.
מה קרה? לפעמים ישר אנחנו יכולים לראות את האזור הבעייתי ולפעמים אנחנו מגלים שאנחנו תלויים ברכיב אחר (שרת מסוים/Database/דף שיעלה בדפדפן וכו').
אם ה- test שלנו תלוי ברכיבים אחרים ובקבלת תשובה מהם, sleep הוא רעיון גרוע מאוד.
העניין בתלות ברכיבים שונים הוא שקצב חזרת התשובה מהם משתנה מאוד (בגלל שוני במערכת הפעלה/תוכנה/חומרה/דפדפן/מהירות אינטרנט וכו'). כך אף פעם לא נוכל באמת לדעת כמה אנחנו צריכים לחכות!
במקום המתנה של זמן מסוים, נרצה להמתין הפעם לתנאי מסוים. אם לדוגמה אנחנו מריצים אוטומציה עבור אפליקציית web, והמשך הריצה שלנו תלוי בהופעה של אלמנט מסוים בדף. אנחנו לא נחכה לפי זמן אלא נמתין עד הרגע שהאלמנט יופיע באמת.
במקרים רבים בהם נכתוב באמצעות כלי אוטומציה קיימים כמו selenium, נוכל להשתמש בפונקציות ה wait הקיימות.
במקרים אחרים פשוט נכתוב פעולה אשר תקבל תנאי, ותמתין עד שהוא יקרה. הפעולה תחזור אם התנאי הפך True או אם הזמן שהוקצב לפעולה נגמר.
כמו שכבר כתבתי בעבר, תרחישי בדיקה הם קוד, בקוד יש באגים, ובאגים צריך לתחקר. באמצעות לוג עבור כל פעולה שאנחנו מבצעים נוכל תמיד לתחקר את התקלות שלנו ולפתור אותן בקלות רבה יותר.
אני אוהב לכתוב לוג לפעולות שלי בדרך הבאה:
bool LoggedMethod(string str1, string str2)
{
log.info($"Started logged method with parameters - str1: {str1}, str2: {str2}")
bool returnValue = *method logic*
log.info($"LoggedMethod return value is: {returnValue}")
return returnValue
}
בפעולה הכתובה למעלה, במידה והיא עושה רק דבר אחד, אני מדפיס ללוג פעם אחת בתחילת הפעולה את שם הפעולה שאני מריץ ואת הפרמטרים שהתקבלו. בסוף הפעולה אני רושם ללוג את הערך שמוחזר מהפעולה רגע לפני החזרתו.
חשוב לזכור - אין דבר כזה יותר מדי לוגים! (כמובן שחשוב לסווגם)
לוגים הם אולי לא פתרון ישיר לייצוב האוטומציה שלנו, אך הם יכולים לתת לנו מידע רב לגבי הנפילות שלנו וכך נוכל להבין הרבה אודות כישלונות אקראיים.
כמובן שאת הלוגים חשוב מאוד לשמור לאורך זמן ורצוי גם לבצע מניפולציות על המידע שהצטבר בכדי להבין מגמות
אין ספק שקיימות דרכים רבות לייצוב תרחישי האוטומציה שלנו אז השתדלתי התמקד במספר פעולות פשוטות. הדרכים שציינתי מהירות לביצוע ועשויות להביא לשינוי גדול. ביצוע הבדיקות הנ"ל יקדם מאוד אותנו מאוד ביציבות התרחישים שלנו ויתרון רבות למערכת הבדיקות שלנו.
הודעתך לא התקבלה - נסה שוב מאוחר יותר
Oops! Something went wrong while submitting the form