טסטים ללא API KEY

אין צד יותר אחורה מזה.
יש קדימה db_cleanup.

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

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

לזה התכוונת?

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

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

רגע, בלי לקפוץ למסקנות בבקשה

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

מה שהפונקציה get_current_year_events עושה זה מביאה את האירועים מgoogle calendar api
ומכניסה אותם לדטה בייס לטבלת אירועים בשביל שיהיה קל לרנדר אותם.

זה כבר נושא אחר שנצטרך להתייחס אליו בהמשך – עצם השימוש בו’ החיבור כאן:

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

בוא ננסה קודם לתפור את הטסטים לחלק הראשון – זה שמביא את האירועים מ־google calendar api.
מה חסר לך כדי שכן תוכל לבנות עבורו טסט?

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

אני צריך גישה לAPI או לmock.
לא תהיה לי גישה לAPI גם ככה שאני אעלה לגיט כי לא יהיה API KEY…
וmock אני לא מצליח ליצור…

אז הרעיון הבא זה לקחת את הפורמט json של אירועים של google calendar, ליצור כמה אובייקטים שמדמיים את האירועים שמגיעים מהAPI ולתת לזה לרוץ.

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

מעולה

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

באיזה שלב עצרת? מה עשית שלא עבד בניסיון ליצור Mock?

מה לדעתך ההבדל בין מה שתיארת לבין Mock?

בתוצאת הסופית אין הבדל.
פשוט mock מדמה איך הכל עובר ברשת.

אם זה בסדר לעשות דוגמאות של אירועים עם הפורמט של google calendar api, אז אני יכול לעשות את זה.

המונח Mock מתאר אובייקט שמחקה אובייקט אותנטי, זה הכל :slight_smile:

לא לגמרי עקבתי. תוכל בבקשה להסביר מה זה אומר אירועים עם הפורמט של Google Calendar API?

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

זה בדיוק Mock, זה נשמע לי נהדר

לייק 1

חחחחחח אני לא מאמין!

תודה רבה על העזרה ים :raised_hands:

לייק 1

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


הדבר הראשון שרציתי זה לחקות את build – כיוון שהיא הפונקציה הראשונה שלא הצלחתי לכתוב לה טסט באופן מיידי.

הבעיה היא ש־build מתחברת לאינטרנט, ואנחנו לא אוהבים בדיקות שמתחברות לאינטרנט מהרבה סיבות:

  1. בקשות רשת זה דבר איטי, וזה יעכב אותנו מאוד כל פעם שנרצה להריץ את הבדיקות.
  2. הרבה פעמים בקשות API עולות כסף. נעדיף לחסוך ולא לשלם על הבדיקות.
  3. הרבה פעמים יהיה rate limit – נניח עד 100 בקשות ליום. גם במקרה הזה נעדיף לחסוך.
  4. התלות במשאב חיצוני יוצרת חוסר דטרמיניסטיות שמועד לפורענות – יכול להיות שהאתר שניסינו להתחבר אליו נפל, או שאין לנו אינטרנט. עדיף להימנע מהמצב שהטסטים לא עובדים בגלל דברים כאלו.

אז אנחנו מבינים שצריך משהו שיחליף את build במהלך הטסט, כך שהיא תתנהג דומה – רק בלי התחברות לאינטרנט.
איך אנחנו מגדירים “תתנהג דומה”?
התשובה היא שמדובר בפונקציה, ואנחנו מגדירים “התנהגות של פונקציה” כ(פחות או יותר) – עבור קלט X הפונקציה תחזיר Y.
כלומר, נגיד ש־build מתנהגת דומה אם עבור הפרמטרים שהיא מקבלת היא תחזיר לנו פלט “רגיל”, כאילו הייתה מחוברת לאינטרנט.

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

הראשונה נקראת Mock, שמשמעו לחקות.
אנחנו למעשה הולכים ליצור אצלנו תשובה שנראית בדיוק כמו התשובה ש־build הייתה מחזירה לנו לו הייתה מחוברת לאינטרנט.
איך נעשה את זה? נתחבר לאינטרנט, נשלח בקשה בעזרת build ונשמור את התשובה שחזרה ממנה איכשהו.
התוצר שנשמר נקרא ה־Mock object – איזשהו אובייקט לא אמיתי, שמחקה את האובייקט האמיתי.
זה אובייקט שדומה מאוד לאובייקט שהיינו מקבלים מ־build האותנטית לו היינו מחוברים לאינטרנט.

אחרי שיצרנו אובייקט שדומה למה ש־build הייתה מחזירה, אנחנו אמורים לגרום לה באמת להחזיר אותו במקרה של הטסטים.
כלומר: ש־build לא באמת תשלח קריאה לאינטרנט, אלא פשוט תחזיר את ה־Mock object שיצרנו.
התהליך שאנחנו הולכים לבצע נקרא Monkey patching.
זה תהליך שבו אנחנו משפיעים על קוד מסוים מבחוץ – כשמאיזושהי סיבה אנחנו לא יכולים/רוצים לערוך את הקוד המקורי.
זה המצב בבדיקות שלנו: אנחנו לא רוצים לערוך את build או את הפונקציה שאנחנו בודקים, אבל אנחנו כן רוצים ש־build תתנהג שונה במלך ריצת הבדיקות.

לעבודה.


דבר ראשון התחלתי בלחפש קצת חומר על Google Calendar API כדי להבין עם מה יש לי עסק.
הגעתי ל:

  1. תיעוד הרשמי שכאן דרך חיפוש בגוגל, שמסביר איך משתמשים ב־Mock objects, אבל לא איך מייצרים אותם. ראיתי שהם משתמשים בשני קבצים שנקראים books-discovery.json ו־books-android.json
  2. הגעתי לאיזו שאלה ב־S/O שמדברת על ה־Discovery Service, ושמתי לב שזה גם השם של המודול שממנו את ה־build. עוד קצת בירורים ונראה שאפשר להשיג מהקישור האחרון ממש את ה־JSON שיוחזר מ־build. זה מושלם ל־Mock שלנו.

לקחתי את ה־JSON שקיבלתי ודחפתי אותו ב־calendar-disocovery.json.
לא לפני שוידאתי שה־API Key או פרטים מזהים חשובים אחרים שלי לא נמצאים שם.

ואם כבר יש ממשק מצחיק כזה שמוציא JSON־ים מתנה, אולי יהיה אחד כזה גם עבור הבקשה השנייה (service.events) – ואכן, יש כזה – והוא אפילו מאפשר להזין פרמטרים כמו בקוד המקורי.

נשבע בזקנו של מרלין שזה לא לקח יותר מחצי שעה של חיפוש.

לא שוכחים להעיף דברים אישיים ו־API Keys אם יש, ושומרים כ־calendar-linux.json (או כל שם אחר שבא לנו).

עכשיו אפשר להשתמש ממש בקוד שהופיע במאמר של גוגל:

from googleapiclient.http import HttpMock
import pprint

http = HttpMock('calendar-discovery.json', {'status': '200'})
service = build('calendar', 'v3', http=http)
request = service.events().list(calendarId='primary',
        timeMin=datetime(2021,1,1).isoformat(),
        timeMax=datetime(2022, 1, 1).isoformat(),
        singleEvents=True,
        orderBy='startTime'
)
http = HttpMock('calendar-linux.json', {'status': '200'})
response = request.execute(http=http)
pprint.pprint(response)

עובד בובה.


נגמר לי הדלק להיום, אז אם codecov יראה שלא הגעת לכל הנקודות בקוד ולא יהיה מרוצה –
משאיר לך להבין איך עושים את ה־Monkey patching בעצמך :slight_smile:

11 לייקים

וואוו תודה רבה !!! :grin:

היי ים אכן codecov עושה לי בעיות, ועשיתי לפונקציות שדורשות קשר עם השרת Monkey patching אך עדיין codecov מסמן לי המון דברים באדום, יש דרך מסויימת שאני צריך לעשות את הMonkey patching כדי שיעבוד עם codecov?

תודה :slightly_smiling_face:

  1. מה ניסית לעשות?
  2. איפה קראת?
  3. אילו קטעי קוד כבר כתבת?