היום נשחק במשחק החביב עלי – לרדת על VBScript. ספציפית נעסוק בחוסר היכולת של VBScript לעבוד עם אובייקטים מסוימים העטופים בממשק (Interface). לאחרונה הבנתי (בין היתר בעקבות
שאלה ב-SQAForums) שהרבה אנשים נתקלו בבעיה הזאת, מבלי להיות מודעים לעומק שלה, והחלטתי שהגיע הזמן לכתוב באופן מסודר איך אני מתמודד איתה.
לפני הכל קצת רקע: VBScript אמנם נתפסת כשפה דלה ועלובה ביחס לשפות תכנות "אמיתיות", אולם בפועל היא יכולה לעבוד עם אובייקטים מתוחכמים שנכתבו בשפות עילית רבות. כך שאם לדוגמה יש לנו אובייקט עם ממשק COM, ניתן ליצור אותו ב-VBScript באמצעות פקודת CreateObject, ולהשתמש בו בלי בעיה. באופן דומה, אם יש לנו DLL שנכתב ב-.Net, ניתן ליצור אותו ב-QTP באמצעות פקודת DotNetFactory, ולעבוד איתו ב-VBScript באופן מלא. הקלות הזו עשויה לגרום לנו להאמין שאין סוג אובייקט ש-VBScript לא יכולה לעבוד איתו, ואולי העובדה ש-QTP מבוסס VBScript היא לא בעיה כל-כך גדולה.
לצערנו, זוהי
טעות. ישנם אובייקטים שמורכבים מידי ל-VBScript, וכפועל יוצא לא ניתן לעבוד איתם ב-QTP. מדובר בסוג מסויים של ממשקים (Interfaces), העוטפים את האובייקטים האמיתיים באפליקציה, ומסתירים אותם מ-VBScript. אם המונח Interface לא מוכר לכם, אל תדאגו – אין צורך בכך על מנת להבין את עצם הבעיה (ואם הוא כן מוכר לכם, אל תזדעזעו מכך שאני מתייחס אליהם כאל סוג של אובייקטים – הכל נעשה למען הפשטות והבהירות). בשורה התחתונה, הרבה אפליקציות מורכבות עובדות עם סוג האובייקטים הזה, והמשמעות היא שיש הרבה אפליקציות שעולמן הפנימי נותר חסום בפנינו.
דוגמה אחת לבעייתיות הזאת הפריעה לי במשך כמעט שנה. כאשר מנסים לכתוב אוטומציה לאפליקציות מבוססות ESRI (גיאוגראפיות), זקוקים לאורדינאטות של האזור המוצג במפה. וזה חבל, כי אובייקט המפה הוא בדיוק מסוג האובייקטים הבעייתיים שלנו, ולכן לא משנה כמה ננסה, לא נצליח להשיג את המידע הדרוש.
איך אפשר לדעת האם האובייקט שאתם מנסים לגשת אליו הוא אובייקט מסוג זה? הדרך המהירה ביותר היא לנסות לגשת אליו מתוך QTP. רק צריך להריץ תסריט ממנו אפשר להגיע לאובייקט הרלוונטי, ולעצור אותו (באמצעות Break Point). נכנס לחלון ה-Debug, ונבקש לראות את האובייקט שם. בשלב זה נראה שמדובר באובייקט רגיל, היות ו-QTP מציג את הערך שלו כ- (Object). אבל אם ננסה לגשת לאחת התכונות הפנימיות של האובייקט (לדוגמה QTPObject.Object.SuspectROObject.SomeProperty), נגלה ש-QTP זורק שגיאת "Object Needed). כלומר, QTP יודע שמדובר באובייקט, אבל לא מסוגל "לדבר" איתו. אובייקטים מסוג זה יופיעו כסוג-משתנה 13 (VarType 13 – vbDataObject).
אמנם, כיום מדובר בבעיה לא נפוצה, המופיע בעיקר במערכות מורכבות מאוד. אולם, בהתחשב בכיוון אליו הולכות שפות התכנות הפופולאריות, סביר להניח ש בשנים הקרובות היא תהפוך לבעיה מרכזית יותר ויותר. נראה כיצד ניתן להתגבר עליה. אני מצאתי שלושה מעקפים:
לנסות לגרום לזה לעבוד: כאן מגיע גילוי נאות – אני לא יודע ש-VBScript לא מסוגל לעבוד עם האובייקטים האלו, אלא וויתרתי על למצוא דרך לעשות זאת. לקח לי כמעט שנה להתייאש, ואני ממש אשמח לשמוע שמישהו הצליח למצוא פתרון אמיתי לבעיה.
לכתוב הרחבת .Net ל-QTP (Extensibility): ה-Add-in של .Net מאפשר לכתוב הרחבות לאובייקטי .Net לא מוכרים. ההרחבות מבוססות C#, ולכן הן חופשיות מהמגבלות והבעיות של VBScript. ספציפית הן גם יכולות לעבוד עם האובייקטים הבעייתים. מידע נוסף בנושא כתיבת הרחבות .Net אפשר למצוא בקבצי העזרה של QTP.
לכתוב פונקציה ב-DLL חיצוני: המעקף הזה דומה לכתיבת הרחבה, אבל הוא פשוט בהרבה וקל לביצוע. אפשר לכתוב פונקציה ב-.Net המקבלת אובייקט בעיתי, עובדת איתו, מפיקה ממנו את המידע הדרוש לנו, ומחזירה אותו באריזה ש-VBScript יודע להתמודד איתה. לרוב זאת משימה אפשרית, היות ובשורה התחתונה, המידע הדרוש הוא כמעט תמיד מספר, מחרוזת או מערך (לדוגמה, אם האובייקט שלנו הוא נקודה גיאוגראפית, המידע הדרוש הוא שני מספרים – אורדינאטות X ו-Y, וניתן להבנות אותו כמערך).
ברגע שהפונקציה כתובה וארוזה כ-DLL, אפשר ליצור אותה בתוך QTP (באמצעות פקודת DotNetFactory), ומרגע זה אין בעיה לקרוא לפונקציה, להעביר אליה את האובייקט הבעייתי כפרמטר, ולקבל ממנה את המידע הדרוש.