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

אז אחרי שבפוסט הקודם הבנו את החשיבות של שילוב קבצי קונפיגורציה בתרחישי האוטומציה שלנו, היום נצלול מעט יותר לעומק הדברים ונכיר דרך יותר מקובלת להשתמש בקבצי קונפיגורציה - קבצי Json. על מנת שנוכל להבין יותר טוב את המדריך חשוב להכיר קודם את הנושאים הבאים:
דוגמה ב C# לשימוש בקבצי Json כקונפיגורציה
בדוגמה אציג מקרה עליו כבר דיברנו בעבר - החלטה של הדפדפן עליו ארצה לבצע את בדיקות האוטומציה של המערכת הנבדקת וה-URL של האתר אליו נרצה לגלוש לצורך ביצוע הבדיקות * חשוב לי לציין שהמטרה כאן איננה לדבר על שימוש בסלניום או עבודה עם WebDriver, מטרת המאמר היא שנבין איך נכון יותר לעבוד עם קבצי קונפיגורציה.
אז למה דווקא Json?
שתי האופציות העיקריות לקונפיגורציה היום הן Json ו-XML. בשנים האחרונות העולם נוטה יותר לשימוש בקבצי Json בעיקר בגלל נוחות הכתיבה הקריאה וההבנה שלהם.

1. התרחיש הראשי שלנו
כאשר אני כותב תרחישי אוטומציה (וקוד בכלל) אני אוהב לכתוב את כל הקוד לפי ההתנהגות (Outside-In).
זאת אומרת, שקודם כל אכתוב את התרחיש (כאשר הפעולות עדיין לא ממומשות) ומשם אפנה לכתיבת המימוש.
כך בעצם אני מסדר את הפעולות בראש שלי יותר טוב וגם דואג לא לממש קוד שלא אצטרך להשתמש בו.
static void Main(string[] args)
{
IConfigReader configReader = new ConfigReader(); //יצירת אובייקט המתעסק עם קבצי הקונפיגורציה
ScenarioConfig scenarioConfig = configReader.ReadScenarioConfigFile(ConfigConstants.ScenarioFilePath); //קריאה לפעולה של ההופכת את קובץ הקונפיגורציה לאובייקט בסישארפ
IBrowser browser = BrowserFactory.GetBrowser(); //יצירת אובייקט דפדפן באמצעות factory
browser.GoToUrl(scenarioConfig.Url); //קריאה לפעולת גלישה עם הערך מקובץ הקונפיגורציה
}
סדר הפעולות כאן די ברור, עכשיו מה שאנחנו צריכים לעשות זה לממש כל חלק בתרחיש.
2. יצירת מודל לקובץ הקונפיגורציה ScenarioConfig
ScenarioConfig יהיה קובץ בו נגדיר מאפיינים של הריצה שלנו - לצורך הדוגמה, Url אליו נפנה בתכנית.
public class ScenarioConfig
{
public string Url { get; set; }
}
חשוב לציין שעל מנת שנוכל להמיר את ה-Json לאובייקט, מודל האובייקט חייב להיות מדויק והקוד שלנו צריך להכיר את המחלקה אליה ה-Json מומר.
3. כתיבת מחלקה שתדע לקרוא את קובץ הקונפיגורציה הזה ולהפוך אותו לאובייקט C#
internal class ConfigReader : IConfigReader
{
private string ReadFile(string filePath)
{
try
{
return File.ReadAllText(filePath);
}
catch (Exception)
{
throw new CouldNotReadFileException();
}
}
private T DeserializeStringToObject<T>(string fileContent)
{
T config = JsonConvert.DeserializeObject<T>(fileContent);
if (config != null)
return config;
else
throw new ConfigObjectIsNullException();
}
public ScenarioConfig ReadScenarioConfigFile(string filePath)
{
return ReadConfigFile<ScenarioConfig>(filePath);
}
}
במחלקה יהיו לעת עתה מספר פעולות:
1. הראשונה היא פעולה שתקבל נתיב של קובץ ותדע להחזיר את תוכן הקובץ.
2. הפעולה השנייה תהיה פעולה גנרית שתהיה גם היא private אשר תקבל גם את סוג הקונפיגורציה אליה תצטרך להמיר את הקובץ ואת תוכן הקובץ ותחזיר אובייקט.
3. הפעולה השלישית תהיה פעולת private גנרית שתקרא לשתי הפעולות הקודמות ובאמצעותן תקרא קובץ ותמיר אותו לאובייקט (פעולה גנרית)
4. הפעולה הרביעית תהיה פעולת Public אשר תחזיר באופן ספציפי את אובייקט הקונפיגורציה ScenarioConfig לאחר שהשתמשה בפעולה השלישית, קראה את הקובץ והפכה אותו לאובייקט.
*כאשר אנחנו מתעסקים בקצבי Json קיימים שני מושגים שחשוב שנכיר: 1. Serialize - הפיכת אובייקט ל-Json string (בדרך כלל לצורך העברתו כמידע) 2. Deserialize - הפיכת Json string ל-אובייקט (בדרך כלל לצורך קריאתו וביצוע פעולות)
4. מימוש BrowserFactory
כעת נרצה לממש מחלקה אשר תהיה אחראית להחזיר לנו את הדפדפן שעליו אנחנו רוצים לעבוד.
המחלקה תחליט מיהו הדפדפן על פי קריאה מקובץ הקונפיגורציה.
enum Browser
{
Firefox,
Chrome,
}
internal class BrowserFactory
{
static Browser GetBrowserEnum(string browser)
{
switch (browser)
{
case "Firefox":
return Browser.Firefox;
case "Chrome":
return Browser.Chrome;
default:
throw new InvalidBrowserException();
}
}
internal static IBrowser GetBrowser()
{
IConfigReader configReader = new ConfigReader();
string browser = configReader.ReadBrowserConfigFile(ConfigConstants.BrowserFilePath).Browser;
switch (GetBrowserEnum(browser))
{
case Browser.Firefox:
return new FirefoxBrowser();
case Browser.Chrome:
return new ChromeBrowser();
default:
throw new InvalidBrowserException();
}
}
}
ניתן לראות שקיים גם enum של סוגי הדפדפנים (זאת על מנת להגביל את השימוש - אחרת הפעולה תוכל לקבל כל string ולנסות להמיר אותו לדפדפן.
וכן גם פעולה אשר ממירה את ה-string שהתקבל מקובץ הקונפיגורציה ל-enum.
5. מימוש המודל BrowserConfig
BrowserConfig יהיה המודל בו נגדיר את מאפייני הדפדפן שלנו (כרגע סוגו של הדפדפן)
public class BrowserConfig
{
public string Browser{ get; set; }
}
6. יצירת מחלקה ConfigConstants
מידע אשר אינו משתנה כקובץ קונפיגורציה אלא פשוט מכיל מידע חשוב שהתכנית שלנו משתמשת בו יש לשים בקובץ Constants - זו כמובן העדפה אישית שלי.
internal class ConfigConstants
{
internal static readonly string ScenarioFilePath = @"c:\configs\scenarioConfig.json";
internal static readonly string BrowserFilePath = @"c:\configs\browserConfig.json";
}
כעת אנחנו מספקים לאזורים בקוד המשתמשים בקבצי הקונפיגורציה את הנתיבים שלהם.
7. מימוש מחלקות הדפדפנים Chrome ו- Firefox
עכשיו נרצה לממש את המחלקות שירשו מה-interface IBrowser זאת לשם שנוכל לעבוד עם הממשק בצורה פולימורפית. כלומר, נרצה לאתחל כ-IBrowser איזה דפדפן שנקבל מה-BrowserFactory שלנו.
internal interface IBrowser
{
void GoToUrl(string url);
}
internal class ChromeBrowser : IBrowser
{
public void GoToUrl(string url)
{
Console.WriteLine(quot;Chrome: going to url - {url}");
}
}
internal class FirefoxBrowser : IBrowser
{
public void GoToUrl(string url)
{
Console.WriteLine(quot;Firefox: Going to url - {url}");
}
}
8. הרצת הפרוייקט
*הערה - ישנם קבצים פשוטים כמו Exceptions ו Interfaces שבחרתי לא להציג את מימושם בפוסט בשביל לא להעמיס על התוכן. כעת נשאר להריץ את הפרויקט במגוון צורות קונפיגורציה ולראות כיצד שינוי הקבצים משנה את פלט התכנית שלנו.
לדוגמה - נריץ את התכנית בעבור הקונפיגורציות הבאות

והפלט שנקבל יהיה כדלקמן -

והרי לנו שימוש בקבצי Json כקונפיגורציה!
סיכום
היום למדנו כיצד משתמשים נכון בקבצי קונפיגורציה באמצעות Json.
מה שיפה בעיני בסוג הקונפיגורציה הזה הוא שכל שפת תכנות היום יודעת לקרוא קבצי Json וכך קובץ הקונפיגורציה לא נשאר תלוי בשפה איתה אנחנו עובדים.
אני קורא לכם לראות איפה אתם משתמשים בקונפיגורציה מתוך מחלקות, מתוך קבצים שתלויים בשפה או כ hard coded ולבחון האם כדאי לכם להמיר את הקונפיגורציה הזו ל Json.
נתראה בפוסט הבא :)