AICODEAgentic Programming · 67723 · 2026-7

Week 5 · video 5 of 8 · transcript

What Tests Cost, and Which Ones to Keep

תרגום שנעשה בעזרת בינה מלאכותית.AI translation, not reviewed by a person.

0:01

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

0:30

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

0:47

עכשיו נשנה התנהגות אחת. אתם עורכים את התוכנה, כי זה השינוי שהתכוונתם לעשות.

0:53

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

1:02

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

1:10

בואו נעקוב אחרי טסט אחד לאורך כל חייו. כותבים אותו פעם אחת, וביום הכתיבה זה כל המחיר.

1:18

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

1:38

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

2:05

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

2:16

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

2:30

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

2:41

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

3:07

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

3:18

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

3:32

קִשרו את הטסטים להתנהגות ונתקו אותם מהמבנה. טסטים שנכתבים ככה מאפשרים לכם לעשות ריפקטורינג למימוש ולהמשיך לבדוק את מה שהקוד שקורא לו צריך.

3:42

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

4:06

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

4:24

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

4:36

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

4:48

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

5:12

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

5:31

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

5:38

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

5:55

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

6:17

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

6:28

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

6:46

והנה המקרה המזיק. הטסט הזה אמור לבדוק שהסכום בקופה כולל מס. אבל הוא מחליף את חישוב המס שלנו עצמנו במוק, ואומר למוק להחזיר 118.

6:59

ואז ה-assert בודק שיצא 118, המספר שהטסט עצמו הגדיר. חישוב המס האמיתי אף פעם לא רץ, ולכן הטסט היה עובר גם אם החישוב הזה היה שגוי או מחוק.

7:11

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

7:47

הסירו את השורה הזאת באופן זמני. התוכנה מקבלת עכשיו פריט ריק, ולכן טסט שמכסה את המצב הזה אמור להיכשל.

7:55

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

8:06

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

8:22

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

8:48

לעשות את זה ידנית לכל שורה ייקח הרבה זמן. כלי יכול לעשות את השינויים המכוונים האלה בשבילכם. הוא עושה שינוי קטן אחד בקוד בכל פעם, ומריץ את הטסטים מול כל גרסה משונה של התוכנה. כל שינוי כזה נקרא מוטציה, והטכניקה כולה נקראת בדיקות מוטציה. ב-Python, כלי בשם mutmut עושה את זה. ב-JavaScript וב-TypeScript יש את Stryker.

9:14

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

9:41

מאמר של גוגל מ-2021 מתאר בדיקות מוטציה שמשמשות יותר מ-24 אלף מפתחים ביותר מאלף פרויקטים.

9:51

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

10:05

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

10:31

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

10:42

ציפייה בלתי תלויה מגיעה במקום זה מהדרישה. שני פריטים של 50 כל אחד הם 100, ועם 18 אחוז מס מגיעים ל-118. טסט שמוודא 118 נכשל על הקוד הנוכחי, ומצביע ישר על המס החסר.

11:00

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

11:21

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

11:37

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

11:59

הטסט הזה קורא ל-initials עם Alan Turing ומדפיס את מה שחוזר, בלי שום assert. כל שורה בפונקציה initials רצה, ולכן כיסוי השורות שלה הוא 100 אחוז.

12:10

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

12:23

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

12:35

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

12:56

בדוח יש שורה אחת לכל קובץ. היא מראה כמה פקודות יש בקובץ, כמה מהן אף פעם לא רצו, ואיזה אחוז מהן כן רצו. העמודה האחרונה היא השימושית ביותר. היא מציינת את השורות שאף טסט לא הריץ. כאן, שורות 42 עד 47 במודול המשימות אף פעם לא רצו.

13:16

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

13:34

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

13:47

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

13:58

גם השלישי קורא ל-initials, אבל עם שם ריק. זה מקרה אחר עם תוצאה צפויה משלו, אז הוא נשאר, למרות שהוא קורא לאותה פונקציה.

14:08

הרביעי מריץ את initials ולא בודק כלום. הוא מוסיף כיסוי, אבל לא יכול להיכשל על תשובה שגויה.

14:15

שפרו אותו על ידי הוספת ערך צפוי. עכשיו תשובה שגויה תכשיל אותו.

14:20

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

14:38

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

14:50 of video · 1,937 words · 56 slides← Back to the video