תגיות: , , , ,
תגובה אחת

בפוסט הקודם ראינו דוגמה פשוטה לכתיבת יחידת בדיקה, Unit Test.

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

לדוגמה: אני רוצה לבדוק איזושהי מתודה פשוטה שמשתמשת במידע שהגיע מה DB. ב TEST עצמו אין לי DB על מנת לבדוק איתו וגם אם היה לי, אני לא באמת רוצה להריץ אותו עם כל מה שזה אומר, רק בשביל הבדיקה הפשוטה.

בשביל מקרים כאלה ישנם FrameWorks המדמים אובייקט מסויים למרות שהאובייקט לא באמת קיים. למעשה, נוצר מאחורי הקלעים PROXY של האינטרפייס שאיתו אני רוצה לעבוד.

נדגים את השימוש בעזרת ה FrameWork שניתן להורדה מNuGet ונקרא Mock (מלשון Mocking = חקוי).

נניח שהקלאס שלי נראה ככה:

 

   1: public class UnitOfTest

   2:    {

   3:        public string Name { get; set; }

   4:  

   5:        public void GetIPerson(IPerson person)

   6:        {

   7:             Name = person.Name;

   8:        }

   9:    }

יש לי Property בשם Name המאותחל בתוך מתודה המקבלת מישהו שמממש אינטרפייס IPerson.

במקום ליצור בטסט מימוש של האינטרפייס הזה בקלאס חדש ואיתו לבדוק – פשוט ניצור Mock של האינטרפייס הזה, נאתחל את Name, ועם הMock הזה נקרא למתודה אותה אנחנו בודקים.

זה נראה כך:

ניצור Property של Mock –

 

   1: private Mock<IPerson> _personMock;

ניצור מתודת Setup שהיא מסוג TestInitialize ומאתחלת ערכים לכל טסט בנפרד –

 

   1: [TestInitialize]

   2:       public void SetUp()

   3:       {

   4:           _personMock = new Mock<IPerson>();

   5:           _personMock.Setup(x => x.Name).Returns("KUKU");

   6:       }

כפי שאפשר לראות, בשורה הראשונה יצרנו מופע של ה Mock והגדרנו שהוא מסוג האינטרפייס IPerson.

שימו לב – ל Mock מכניסים רק אינטרפייסים ולא קלאסים.

בשורה השניה אתחלנו בעזרת Lambda Expression את המאפיין Name במילה KUKU וזאת למרות שאין לי בכלל קלאס שמממש את האינטרפייס הזה.

במתודה עצמה נכתוב כך:

 

   1: [TestMethod]

   2:       public void TestMethod1()

   3:       {

   4:           var ut = new UnitOfTest();

   5:           ut.GetIPerson(_personMock.Object);

   6:           Assert.AreEqual("KUKU", ut.Name);

   7:       }

בשורה הראשונה יצרנו מופע של הקלאס הנבדק.

בשורה השניה קראנו למתודה GetIPerson עם ה Mock שלנו.

שימו לב שאנחנו לא שולחים את ה Mock עצמו אלא את האובייקט שבתוכו באופן הזה: _personMock.Object

ובשורה השלישית נבדוק בעזרת פקודת Assert שאכן הName אותחל כמצופה במילה KUKU.

.

.

.

הטסט כמובן עובר!

 

Capture

 

הקוד בשלמותו נראה כך (אם כי במצב נכון, הטסט והקלאס יושבים בפרוייקטים נפרדים):

   1: using Microsoft.VisualStudio.TestTools.UnitTesting;

   2: using Moq;

   3:  

   4: namespace MockExample

   5: {

   6:     [TestClass]

   7:     public class UnitTest1

   8:     {

   9:         private Mock<IPerson> _personMock;

  10:  

  11:         [TestInitialize]

  12:         public void SetUp()

  13:         {

  14:             _personMock = new Mock<IPerson>();

  15:             _personMock.Setup(x => x.Name).Returns("KUKU");

  16:         }

  17:  

  18:  

  19:         [TestMethod]

  20:         public void TestMethod1()

  21:         {

  22:             var ut = new UnitOfTest();

  23:             ut.GetIPerson(_personMock.Object);

  24:             Assert.AreEqual("KUKU", ut.Name);

  25:         }

  26:     }

  27:  

  28:     public class UnitOfTest

  29:     {

  30:         public string Name { get; set; }

  31:  

  32:         public void GetIPerson(IPerson person)

  33:         {

  34:              Name = person.Name;

  35:         }

  36:     }

  37:  

  38:     public interface IPerson

  39:     {

  40:         string Name { get; set; }

  41:     }

  42: }

  43:  

  44:  

הסבר זה היה רק על קצה המזלג, על מנת להבין את דרך העבודה.

אפשרויות רבות וטובות לשימוש בMock אפשר למצוא כאן.

הוסף תגובה " class="ir icon-in">linkedin twitter email