כיצד להשתמש ב- Moq כדי להקל על בדיקות היחידות ב- C #

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

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

תחילת העבודה עם Moq

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

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

Install-Package Moq

כיצד ללעוג לממשקים באמצעות Moq

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

Mock mockObjectType = Mock mock ();

עכשיו שקול את הממשק הבא בשם IAuthor.

ממשק ציבורי IAuthor

    {

        int מזהה {get; מַעֲרֶכֶת; }

        מחרוזת FirstName {get; מַעֲרֶכֶת; }

        מחרוזת LastName {get; מַעֲרֶכֶת; }

    }

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

var mock = Mock new ();

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

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

var author = Mock new ();

author.SetupGet (p => p.Id). מחזיר (1);

author.SetupGet (p => p.FirstName). מחזיר ("ג'וידיפ");

author.SetupGet (p => p.LastName) .Returns ("Kanjilal");

Assert.AreEqual ("ג'וידיפ", מחבר. אובייקט.FirstName);

Assert.AreEqual ("Kanjilal", author.Object.LastName);

כיצד ללעוג לשיטות באמצעות Moq

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

מאמר בכיתה ציבורית

    {

        DateTime וירטואלי ציבורי GetPublicationDate (int articleId)

        {

            לזרוק NotImplementedException חדש ();

        }

    }

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

var mockObj = Mock new ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). מחזירה ((int x) => DateTime.Now);

שיטת ההתקנה משמשת להגדרת התנהגות של שיטה המועברת אליה כפרמטר. בדוגמה זו, הוא משמש להגדרת התנהגותה של שיטת GetPublicationDate. הקריאה ל- It.IsAny()מרמזת על כך ששיטת GetPublicationDate תקבל פרמטר מסוג שלם; Itמתייחס למעמד סטטי. משתמשים בשיטת החזרות כדי לציין את ערך ההחזרה של השיטה שצוינה בשיחת שיטת ההתקנה. בדוגמה זו, משתמשים בשיטת החזרת כדי לציין את ערך ההחזרה של השיטה כתאריך המערכת הנוכחי.

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

mockObj.Verify (t => t.GetPublicationDate (It.IsAny ()));

כאן אנו משתמשים בשיטת Verify כדי לקבוע אם GetPublicationDate נקרא על האובייקט המדומה.

כיצד ללעוג לשיטות כיתת בסיס באמצעות Moq

שקול את פיסת הקוד הבאה. יש לנו כאן שתי מחלקות - מחלקת RepositoryBase ומחלקת AuthorRepository שמרחיבה אותה.

מחלקה מופשטת ציבורית RepositoryBase

{

    bool וירטואלי ציבורי IsServiceConnectionValid ()

    {

        // קצת קוד

    }

}

מחלקה ציבורית AuthorRepository: RepositoryBase

{

    חלל ציבורי שמור ()

    {

        אם (IsServiceConnectionValid ())

        {

            // קצת קוד

        }

    }

}

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

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

var mockObj = Mock new () {CallBase = true};

mockObj.Setup (x => x.IsServiceConnectionValid ()). מחזיר (נכון);

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