AICODEAgentic Programming · 67723 · 2026-7

Week 5 · video 2 of 8 · transcript

Testing: Kinds of Tests, and Having the Agent Write Them

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

0:00

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

0:22

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

0:40

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

0:49

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

0:59

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

1:16

הנה ניסיון ראשון, ב-Python עם pytest וב-TypeScript עם vitest. שום דבר בסרטון הזה לא תלוי בשפה שבה אתם עובדים. שתי הגרסאות קוראות ל-initials ומדפיסות את מה שחוזר. אם initials הייתה מחזירה ZZ, האם אחד הטסטים היה נכשל?

1:33

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

1:43

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

1:51

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

2:01

אז איך בעצם מריצים את הטסטים? כנראה כבר עשיתם את זה בקורסים קודמים, אז הנה ריענון קצר. ב-Python מריצים pytest. ב-TypeScript מריצים npx vitest run. כל runner מוצא ומריץ את הטסטים שנבחרו בהגדרות הפרויקט. אם אתם צריכים יותר מהריענון הזה, חפשו את התיעוד של pytest או של vitest.

2:25

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

2:52

כשמתקנים דבר אחד, כדאי שההרצה תיעצר בכישלון הראשון. ב-pytest זה -x, וב-vitest זה --bail 1.

3:02

הנה דוח מקוצר של pytest עם טסט אחד שנכשל. השורה הראשונה אומרת אילו טסטים ה-runner בחר. הוא אסף שניים. אחריה מגיע סימן אחד לכל טסט: נקודה למעבר ו-F לכישלון. עבור הכישלון, הדוח מציג את ה-assert שלא התקיים, עם שני הערכים. כאן initials החזירה את שתי האותיות באותיות קטנות, והטסט ציפה להן באותיות גדולות. השורות האחרונות מציינות את הטסט שנכשל וסופרות את התוצאות. לדוח של vitest יש אותם חלקים.

3:34

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

3:45

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

3:59

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

4:14

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

4:37

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

4:47

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

5:00

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

5:09

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

5:18

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

5:34

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

5:47

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

6:25

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

6:39

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

6:51

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

7:22

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

7:33

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

7:45

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

8:07

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

8:32

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

8:40

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

8:48

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

9:10

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

9:30

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

9:53

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

10:07

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

10:29

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

10:47

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

11:11

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

11:41

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

11:56

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

12:21

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

12:35

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

12:51

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

13:19

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

13:32 of video · 1,792 words · 47 slides← Back to the video