AICODEAgentic Programming · 67723 · 2026-7

Week 5 · video 4 of 8 · transcript

From Stories to Tests

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

0:01

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

0:30

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

0:47

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

0:55

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

1:07

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

1:29

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

1:40

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

2:06

כדי להפוך את סיפור המשתמש לטסט, חותכים אותו לשלושה חלקים. החלק הראשון מקים את המצב שסיפור המשתמש מניח, שכאן הוא רשימת משימות עם שלושה פריטים: Buy milk, Call mom ו-Pay rent.

2:19

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

2:28

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

2:55

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

3:15

הנה אותם שלושה חלקים כתובים כקוד. הדוגמה כתובה ב-Python ורצה עם pytest. השורה הראשונה קוראת ל-list with, פונקציית עזר קטנה שנכתבה לטסטים האלה. היא בונה רשימה של שלושת הפריטים, שכולם עדיין פתוחים. השורה השנייה שומרת את הרשימה וטוענת בחזרה את הטקסט השמור. הטעינה בונה רשימה חדשה מהטקסט הזה בלבד, בדיוק כמו שאפליקציה חדשה הייתה עושה. הטסט קורא ל-save ול-load ישירות, כפונקציות רגילות, בלי דפדפן. הוא בודק את הקוד של השמירה והטעינה עצמו. הוא לא מראה שכפתור ה-Save בדף מגיע לקוד הזה, ואת זה בודק טסט דפדפן. השורה האחרונה משווה את הרשימה שנטענה לרשימה המקורית, פריט אחר פריט. כך שהיא בודקת כל פריט, את כל מה שרשום על כל אחד מהם, ואת הסדר שלהם. כאן הסדר הוא חלק מהדרישה, כי סעיף אחר קובע שפריטים חדשים נכנסים לתחתית הרשימה, ואסור שהטעינה תשנה את הסדר שלהם.

4:09

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

4:28

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

4:51

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

5:20

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

5:40

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

6:07

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

6:44

הנה טסט לשילוב הזה, באותו מבנה של given, when ו-then. הוא מתחיל משני פריטים פתוחים, Buy milk ו-Call mom. הוא משלים את Buy milk, וזה מה שלחיצה על תיבת הסימון שלו עושה. אחר כך הוא שומר את הרשימה וטוען אותה בחזרה לרשימה חדשה, בדיוק כמו שקורה כשפותחים את האפליקציה מחדש. השורה האחרונה בודקת מה המסנן Active היה מציג. היא קוראת ל-visible items, הפונקציה שמחליטה אילו פריטים מסנן מציג. אנחנו מצפים ל-Call mom לבד. בטסט הזה יש כמה שלבים, אבל הוא בודק תוצאה אחת. כשמריצים אותו על האפליקציה הנוכחית, הוא נכשל, כי Buy milk חוזר כפריט שלא הושלם.

7:22

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

7:41

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

7:53

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

8:29

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

8:43

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

8:57

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

9:07

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

9:20 of video · 1,325 words · 26 slides← Back to the video