ספריות הלקוח של Cloud ל-Rust מספקות דרך ליצור סטאבים של הטמעות לקוח אמיתיות, כדי שתוכלו להחדיר מוק לבדיקה. אתם יכולים להשתמש ב-mocks כדי לכתוב בדיקות יחידה מבוקרות ואמינות שלא מבצעות קריאות לרשת או צוברות חיובים.
במאמר הזה נסביר על הנושאים הבאים:
- איך לכתוב ממשקים שניתנים לבדיקה באמצעות לקוח
Storageשל Cloud Storage. - איך לדמות פעולות קריאה.
- איך לדמות פעולות כתיבה.
- למה העיצוב של הלקוח
Storageשונה מלקוחות Google Cloudאחרים.
יחסי תלות
מוסיפים את ספריית הלקוח של Cloud Storage לקובץ Cargo.toml:
cargo add google-cloud-storage
כדי לקמפל ולהריץ את בדיקות היחידה במסמך הזה, צריך להוסיף את יחסי התלות הבאים לפיתוח:
cargo add --dev anyhow bytes mockall
cargo add --dev tokio --features macros,rt-multi-thread
כתיבת ממשקים שניתן לבדוק
אם אתם לא מבצעים בדיקת יחידה של קוד האחסון, אתם יכולים לכתוב ממשקים ישירות במונחים של Storage, שפרמטר ברירת המחדל של סוג ה-stub שלו הוא הטמעת ה-production של הלקוח:
כדי לבדוק את הקוד באמצעות לקוח מדומה, כותבים את הממשקים במונחים של פרמטר מסוג גנרי T שמוגבל על ידי gcs::stub::Storage + 'static:
פעולות קריאה מדומות
כדי לדמות בקשות של read_object:
כותבים פונקציית אפליקציה שמקבלת לקוח
&Storage<T>גנרי. לדוגמה, הפונקציה הבאה מורידה אובייקט וסופרת כמה תווים של שורה חדשה יש בו:יוצרים פונקציית עזר שבונה זרם בייטים מזויף של
ReadObjectResponseעל ידי העברת מטען ייעודי (payload) אלReadObjectResponse::from_source. השיטה הזו מקבלת את אותם סוגי מטען ייעודי (payload) כמוStorage::write_object:מגדירים מבנה מדומה שמטמיע את
gcs::stub::Storage. במסמך הזה אנחנו משתמשים ב-cratemockall, אבל אתם יכולים להשתמש במסגרת מדומה אחרת בבדיקות שלכם:כותבים בדיקת יחידה שמגדירה את הציפיות מהדמה, יוצרים לקוח באמצעות
Storage::from_stubוקוראים ל-count_newlines:
פעולות כתיבה מדומות
כדי לדמות בקשות של write_object:
כותבים פונקציה של אפליקציה שמעלה אובייקט באמצעות לקוח
&Storage<T>גנרי:באמצעות ה-struct
MockStorageשהוגדר בקטע הקודם, כותבים בדיקת יחידה שמגדירה את הציפיות ב-mock, יוצרת לקוח באמצעותStorage::from_stubוקוראת ל-upload:
פרטי הציפיות
מכיוון שהפונקציה upload קוראת ל-send_unbuffered, מגדירים את הציפייה ב-method expect_write_object_unbuffered התואם:
הפקודה mockall::mock! מתייחסת לכל יצירת מופע גנרי כשיטה נפרדת. מציינים את סוג המטען הייעודי (payload) הקונקרטי, Payload<BytesSource>, בחתימת הסגירה כדי שהקומפיילר יוכל להתאים לציפייה של השיטה:
הסבר לגבי העיצוב
בקטעים הבאים מוסבר למה הלקוח של Storage משתמש בפרמטר מסוג גנרי ל-stub שלו, במקום ב-dynamic dispatch.
לקוחות אחרים
רוב הלקוחות, כמו StorageControl, מחזיקים באופן פנימי בהטמעה תואמת-dyn של מאפיין ה-stub שלהם, שנספרת לפי קובץ עזר (Arc). הם משתמשים ב-dynamic dispatch כדי להעביר בקשות מהלקוח ל-stub הבסיסי, שיכול להיות הטמעה בסביבת הייצור או מדומה.
מכיוון שהלקוחות האלה משתמשים בהקצאה דינמית, המקמפל לא צריך לפתור את סוג ה-stub הקונקרטי בזמן הקימפול, והמבנים של הלקוח לא צריכים פרמטר של סוג גנרי בשביל ה-stub שלהם.
הלקוח Storage
ב-Rust, למאפיין שתואם ל-dyn לא יכולות להיות שיטות גנריות או להחזיר ערכי impl Future לא ארוזים:
- השיטות
write_object_bufferedו-write_object_unbufferedהן כלליות לגבי סוג המקור של המטען הייעודי (payload). - ה-methods של המאפיין
gcs::stub::Storageמחזירות אתimpl Futureישירות במקום להכניס את ה-future המוחזר ל-box.
כדי להשתמש בהקצאה דינמית ללקוח Storage, צריך להוסיף מטען ייעודי (payload) ו-futures לכל קריאה, וגם להוסיף הקצאות זיכרון בערימה (heap allocation) ותקורה של הקצאה דינמית בנתיב הנתונים. כדי להימנע מהתקורה הזו, הלקוח Storage משתמש בפרמטר מסוג מסוים להטמעה קונקרטית של המאפיין gcs::stub::Storage.
קוד אפליקציה מלא וחבילת מקרים לבדיקה
הקוד הבא משלב את הפונקציות של האפליקציה ואת בדיקות היחידה לדוגמה מלאה:
מריצים את cargo test כדי להפעיל את test_count_lines ואת test_upload:
cargo test