Mockito לעומת EasyMock לעומת JMockit

1. הקדמה

1.1. סקירה כללית

בפוסט זה נדבר על לַעֲגָנִי: מה זה, מדוע להשתמש בו וכמה דוגמאות כיצד ללעוג לאותו מקרה בדיקה באמצעות כמה מספריות הלעיג הנפוצות ביותר עבור Java.

נתחיל בכמה הגדרות פורמליות / חצי פורמליות של מושגים לועגים; לאחר מכן נציג את המקרה הנבדק, נמשיך עם דוגמאות לכל ספרייה ונסיים עם כמה מסקנות. הספריות שנבחרו הן Mockito, EasyMock ו- JMockit.

אם אתה מרגיש שאתה כבר מכיר את יסודות הלעג, אולי תוכל לדלג לנקודה 2 מבלי לקרוא את שלוש הנקודות הבאות.

1.2. סיבות להשתמש בלעג

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

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

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

החלפה מבוקרת זו היא לִלְעוֹג, וזה יעזור לך לפשט את קידוד הבדיקה ולהפחית את זמן ביצוע הבדיקה.

1.3. מושגים והגדרה מדומים

בואו נראה ארבע הגדרות ממאמר שכתב מרטין פאולר המסכם את היסודות שכולם צריכים לדעת על לעגים:

  • דֶמֶה אובייקטים מועברים מסביב אך מעולם לא משתמשים בהם. בדרך כלל, הם משמשים רק למילוי רשימות פרמטרים.
  • מְזוּיָף לאובייקטים יש מימושים פועלים, אך בדרך כלל קחו קיצור דרך כלשהו שהופך אותם לא מתאימים להפקה (מסד נתונים בזיכרון הוא דוגמה טובה).
  • תולים לספק תשובות משומרות לשיחות שבוצעו במהלך הבדיקה, בדרך כלל לא מגיבות כלל לשום דבר מחוץ למה שתוכנת למבחן. Stubs עשויים גם להקליט מידע אודות שיחות, כמו למשל שער דואר אלקטרוני שזוכר את ההודעות שהוא 'שלח', או אולי רק כמה הודעות 'שלח'.
  • לועגים הם מה שאנו מדברים כאן: אובייקטים שתוכנתו מראש עם ציפיות ויוצרים מפרט לשיחות שהם צפויים לקבל.

1.4 ללעוג או לא ללעוג: זו השאלה

לא חייבים ללעוג להכל. לפעמים עדיף לערוך בדיקת אינטגרציה שכן ללעוג לשיטה / תכונה זו פשוט יעבוד לטובת תועלת ממשית. במקרה הבדיקה שלנו (שיוצג בנקודה הבאה) שיבחן את ה- LoginDao.

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

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

2. מקרה מבחן

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

2.1 מקרה מוצע

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

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

בדרך זו, יהיה לנו LoginController, א LoginService ו LoginDAO. בואו נראה תרשים להבהרה:

2.2 יישום

נבצע כעת את היישום המשמש למקרה הבדיקה, כדי שנוכל להבין מה קורה (או מה צריך לקרות) במבחנים.

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

מחלקה ציבורית UserForm {סיסמת מחרוזת ציבורית; שם משתמש מחרוזת ציבורי; מחרוזת ציבורית getUsername () {שם משתמש חוזר; }}

בוא נלך עם LoginDAO, זה יהיה מבטל מהפונקציונליות כיוון שרק אנו רוצים שהשיטות שלו יהיו שם כדי שנוכל ללעוג להן בעת ​​הצורך:

מחלקה ציבורית LoginDao {התחברות ציבורית int (UserForm userForm) {return 0; }}

LoginDao ישמש את LoginService ב התחברות שיטה. LoginService יהיה גם setCurrentUser שיטה שחוזרת בָּטֵל לבדוק את הלעג הזה.

כיתה ציבורית LoginService {LoginDao פרטי LoginDao; פרטי מחרוזת currentUser; כניסה בוליאנית ציבורית (UserForm userForm) {assert null! = userForm; int loginResults = loginDao.login (userForm); switch (loginResults) {case 1: return true; ברירת מחדל: להחזיר שקר; }} ריק ריק setCurrentUser (שם משתמש מחרוזת) {if (null! = שם משתמש) {this.currentUser = שם משתמש; }}}

סוף כל סוף, LoginController אשתמש LoginService עבור שלה התחברות שיטה. זה יכלול:

  • מקרה בו לא יבוצעו שיחות לשירות הלעג.
  • מקרה בו ייקרא שיטה אחת בלבד.
  • מקרה בו ייקראו כל השיטות.
  • מקרה בו ייבדקו השלכת חריגים.
מחלקה ציבורית LoginController {public LoginService loginService; כניסה ציבורית למחרוזת (UserForm userForm) {if (null == userForm) {return "ERROR"; } אחר {רשום בוליאני; נסה {loggt = loginService.login (userForm); } לתפוס (חריג ה) {להחזיר "שגיאה"; } אם (מחובר) {loginService.setCurrentUser (userForm.getUsername ()); החזירו "אישור"; } אחר {להחזיר "KO"; }}}}

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

3. הגדרת בדיקה

3.1 מוקיטו

עבור Mockito נשתמש בגרסה 2.8.9.

הדרך הקלה ביותר ליצור ושימוש בלעג היא באמצעות @לִלְעוֹג ו @InjectMocks ביאורים. הראשון ייצור דמה עבור הכיתה המשמשת להגדרת השדה והשנייה תנסה להזריק את הלעג שנוצר ללעג הביאור.

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

עם זאת נאמר, אתה צריך להתקשר MockitoAnnotations.initMocks (זה) לפני ביצוע בדיקות כלשהן שישתמשו בלעג לביצועים כדי שכל ה"קסם "הזה יעבוד. זה נעשה בדרך כלל ב @לפני שיטת ביאור. אתה יכול גם להשתמש ב- MockitoJUnitRunner.

מחלקה ציבורית LoginControllerTest {@Mock התחברות פרטיתDao loginDao; @Spy @InjectMocks פרטי כניסה שירות spiedLoginService; @Mock פרטי LoginService loginService; @InjectMocks פרטי LoginController loginController; @ לפני setUp הריק הציבורי () {loginController = LoginController חדש (); MockitoAnnotations.initMocks (זה); }}

3.2 EasyMock

עבור EasyMock נשתמש בגרסה 3.4 (Javadoc). שים לב שעם EasyMock, כדי שלעג יהיה להתחיל "לעבוד", עליך להתקשר EasyMock.replay (מדומה) בכל שיטת בדיקה, אחרת תקבל חריג.

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

לעגים נוצרים עם ה- @לִלְעוֹג ביאור והאובייקט שנבדק עם @נושא הבדיקה אחד (אשר יקבל את התלות שלו מוזרק מלעג שנוצר). יש ליצור את האובייקט שנבדק באופן מקוון.

@RunWith (EasyMockRunner.class) כיתה ציבורית LoginControllerTest {@Mock כניסה פרטיתDao loginDao; @Mock פרטי LoginService loginService; @TestSubject פרטי LoginController loginController = LoginController חדש (); }

3.3. JMockit

עבור JMockit נשתמש בגרסה 1.24 (Javadoc) מכיוון שגרסה 1.25 עדיין לא פורסמה (לפחות בזמן כתיבת שורות אלה).

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

הלעג מוגדר באמצעות הזרקת ביאור (שייצור מופע מדומה אחד בלבד) או עם @Mocked ביאור (שייצור לעגים לכל מופע של מחלקת השדה המאושר).

המופע שנבדק נוצר (ותלותיו הלעוגית מוזרקת) באמצעות @בָּדוּק ביאור.

@RunWith (JMockit.class) מחלקה ציבורית LoginControllerTest {@Injectable private LoginDao loginDao; @Injectable פרטי LoginService loginService; @Controller פרטי LoginController loginController; }

4. אימות אין שיחות ללעוג

4.1. מוקיטו

כדי לוודא שלמוק לא התקשרו שיחות במוקיטו, יש לך את השיטה verifyZeroInteractions () שמקבל דמה.

@Test ציבורי בטל assertThatNoMethodHasBeenCalled () {loginController.login (null); Mockito.verifyZeroInteractions (loginService); }

4.2. EasyMock

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

@Test הציבור בטל בטל assertThatNoMethodHasBeenCalled () {EasyMock.replay (loginService); loginController.login (null); EasyMock.verify (loginService); }

4.3. JMockit

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

@Test הציבור בטל בטל assertThatNoMethodHasBeenCalled () {loginController.login (null); FullVerifications חדשים (loginService) {}; }

5. הגדרת שיחות שיטת ללעג ואימות שיחות ללעג

5.1. מוקיטו

ל שיחות שיטת לעג, אתה יכול להשתמש Mockito.when (mock.method (טוען)). ואז החזר (ערך). כאן תוכל להחזיר ערכים שונים ליותר משיחה אחת, רק להוסיף אותם כפרמטרים נוספים: thenReturn (value1, value2, value-n, ...).

שים לב שאתה לא יכול ללעוג לשיטות החזרה בטלות עם התחביר הזה. במקרים האמורים, תשתמש באימות של השיטה האמורה (כפי שמוצג בשורה 11).

ל אימות שיחות ללעג שאתה יכול להשתמש בו Mockito.verify (mock) .method (args) ותוכלו לוודא שלא נעשו שיחות נוספות ללעג באמצעות verifyNoMoreInteractions (מדומה).

ל מאמת טיעונים, אתה יכול להעביר ערכים ספציפיים או להשתמש בהתאמות מוגדרות מראש כמו כל(), anyString (), anyInt (). יש הרבה יותר מסוג זה של התאמות ואפילו אפשרות להגדיר את המתאימים שלך, שנראה בדוגמאות הבאות.

@Test ציבורי בטל assertTwoMethodsHaveBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; Mockito.when (loginService.login (userForm)). ואז החזר (נכון); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); Mockito.verify (loginService) .login (userForm); Mockito.verify (loginService) .setCurrentUser ("foo"); } @Test ציבורי בטל assertOnlyOneMethodHasBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; Mockito.when (loginService.login (userForm)). ואז החזר (false); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("KO", כניסה); Mockito.verify (loginService) .login (userForm); Mockito.verifyNoMoreInteractions (loginService); }

5.2. EasyMock

ל שיחות שיטת לעג, אתה משתמש EasyMock.expect (mock.method (args)). והחזר (ערך).

ל אימות שיחות ללעג, אתה יכול להשתמש EasyMock.verify (מדומה)אבל אתה חייב לקרוא לזה תמיד אחרי יִעוּד EasyMock.replay (מדומה).

ל מאמת טיעונים, אתה יכול להעביר ערכים ספציפיים, או שיש לך התאמות מוגדרות מראש כמו isA(Class.class), anyString (), anyInt (), והרבה יותר מסוג זה של שידוכים ושוב אפשרות להגדיר את התואמים שלך.

@Test ציבורי בטל assertTwoMethodsHaveBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; EasyMock.expect (loginService.login (userForm)). וחזור (נכון); loginService.setCurrentUser ("foo"); EasyMock.replay (loginService); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); EasyMock.verify (loginService); } @Test ציבורי בטל assertOnlyOneMethodHasBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; EasyMock.expect (loginService.login (userForm)). ו- Return (false); EasyMock.replay (loginService); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("KO", כניסה); EasyMock.verify (loginService); }

5.3. JMockit

עם JMockit, הגדרת שלבים לבדיקה: הקלטה, הפעלה חוזרת ואימות.

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

ל שיחות שיטת לעג, אתה יכול להשתמש mock.method (טוען); תוצאה = ערך; בתוך כל אחד ציפיות לַחסוֹם. כאן תוכל להחזיר ערכים שונים ליותר משיחה אחת רק באמצעות מחזיר (ערך 1, ערך 2, ..., ערך); במקום תוצאה = ערך;.

ל אימות שיחות ללעג אתה יכול להשתמש באימות חדש() {{mock.call (value)}} אוֹ אימות חדש (מדומה) {{}} כדי לאמת כל שיחה צפויה שהוגדרה בעבר.

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

@Test ציבורי בטל assertTwoMethodsHaveBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; ציפיות חדשות () {{loginService.login (userForm); תוצאה = נכון; loginService.setCurrentUser ("foo"); }}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); FullVerifications חדשים (loginService) {}; } @Test ציבורי בטל assertOnlyOneMethodHasBeenCalled () {UserForm userForm = חדש UserForm (); userForm.username = "foo"; ציפיות חדשות () {{loginService.login (userForm); תוצאה = שקר; // אין ציפייה ל- setCurrentUser}}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("KO", כניסה); FullVerifications חדשים (loginService) {}; }

6. זריקת חריגה לועגת

6.1. מוקיטו

ניתן ללעוג לזרוק חריגים באמצעות .thenTrow (ExceptionClass.class) אחרי Mockito.when (mock.method (טוען)).

@Test ציבורי בטל mockExceptionThrowin () {UserForm userForm = משתמש חדש (); Mockito.when (loginService.login (userForm)). ואז לזרוק (IllegalArgumentException.class); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("שגיאה", כניסה); Mockito.verify (loginService) .login (userForm); Mockito.verifyZeroInteractions (loginService); }

6.2. EasyMock

ניתן ללעוג לזרוק חריגים באמצעות .andThrow (ExceptionClass חדש ()) אחרי EasyMock.expect (...) שִׂיחָה.

@Test ציבורי בטל mockExceptionThrowing () {UserForm userForm = UserForm חדש (); EasyMock.expect (loginService.login (userForm)). AndTrow (חדש IllegalArgumentException ()); EasyMock.replay (loginService); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("שגיאה", כניסה); EasyMock.verify (loginService); }

6.3. JMockit

לזרוק חריג ללעג עם JMockito קל במיוחד. פשוט החזירו Exception כתוצאה משיחת שיטה לעגית במקום ההחזרה "הרגילה".

@Test ציבורי בטל mockExceptionThrowing () {UserForm userForm = חדש UserForm (); ציפיות חדשות () {{loginService.login (userForm); תוצאה = IllegalArgumentException חדש (); // אין ציפייה ל- setCurrentUser}}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("שגיאה", כניסה); FullVerifications חדשים (loginService) {}; }

7. לועג לאובייקט שיעבור

7.1. מוקיטו

אתה יכול ליצור דמה גם כדי לעבור כטיעון לשיחת שיטה. עם Mockito, אתה יכול לעשות את זה עם אניה אחת.

@Test ציבורי בטל mockAnObjectToPassAround () {UserForm userForm = Mockito.when (Mockito.mock (UserForm.class) .getUsername ()) .thenReturn ("foo"). GetMock (); Mockito.when (loginService.login (userForm)). ואז החזר (נכון); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); Mockito.verify (loginService) .login (userForm); Mockito.verify (loginService) .setCurrentUser ("foo"); }

7.2. EasyMock

ניתן ליצור לעגים באופן מקוון עם EasyMock.mock (Class.class). לאחר מכן, תוכל להשתמש EasyMock.expect (mock.method ()) להכין אותו לביצוע, תמיד לזכור להתקשר EasyMock.replay (מדומה) לפני השימוש בו.

@Test ציבורי בטל mockAnObjectToPassAround () {UserForm userForm = EasyMock.mock (UserForm.class); EasyMock.expect (userForm.getUsername ()). ו- Return ("foo"); EasyMock.expect (loginService.login (userForm)). וחזור (נכון); loginService.setCurrentUser ("foo"); EasyMock.replay (userForm); EasyMock.replay (loginService); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); EasyMock.verify (userForm); EasyMock.verify (loginService); }

7.3. JMockit

כדי ללעוג לאובייקט בשיטה אחת בלבד, אתה יכול פשוט להעביר אותו ללעג כפרמטר לשיטת הבדיקה. אז אתה יכול ליצור ציפיות כמו כל דמה אחרת.

@Test ציבורי בטל mockAnObjectToPassAround (@Mocked UserForm userForm) {New Expectations () {{userForm.getUsername (); תוצאה = "foo"; loginService.login (userForm); תוצאה = נכון; loginService.setCurrentUser ("foo"); }}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); FullVerifications חדשים (loginService) {}; FullVerifications חדשים (userForm) {}; }

8. התאמת ארגומנטים בהתאמה אישית

8.1. מוקיטו

לפעמים התאמת ויכוחים לשיחות הלעגיות צריכה להיות מורכבת מעט יותר מסתם ערך קבוע או anyString (). עבור המקרים האלה עם Mockito יש מחלקת התאמה שלה המשמשת עם argThat (ArgumentMatcher).

@Test בטל פומבי @Matching () {UserForm userForm = UserForm חדש (); userForm.username = "foo"; // התאמת ברירת המחדל Mockito.when (loginService.login (Mockito.any (UserForm.class))). ואז החזר (נכון); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); Mockito.verify (loginService) .login (userForm); // התאמה מורכבת Mockito.verify (loginService) .setCurrentUser (ArgumentMatchers.argThat (חדש ArgumentMatcher () {@Override התאמות בוליאניות ציבוריות (ארגומנט מחרוזת) {return argument.startsWith ("foo");}})); }

8.2. EasyMock

התאמת ארגומנטים מותאמת אישית מורכבת מעט יותר עם EasyMock מכיוון שאתה צריך ליצור שיטה סטטית שבה אתה יוצר את ההתאמה בפועל ואז מדווח עליה באמצעות EasyMock.reportMatcher (IArgumentMatcher).

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

@Test בטל פומבי @Matching () {UserForm userForm = UserForm חדש (); userForm.username = "foo"; // התאמת ברירת המחדל EasyMock.expect (loginService.login (EasyMock.isA (UserForm.class))). andReturn (true); // loginService.setCurrentUser matcher מורכב (specificArgumentMatching ("foo")); EasyMock.replay (loginService); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); EasyMock.verify (loginService); } פרטי סטטי מחרוזת ספציפית ArgumentMatching (מחרוזת צפויה) {EasyMock.reportMatcher (IArgumentMatcher חדש () {@Override התאמות בוליאניות ציבוריות (ארגומנט אובייקט) {מופע ארגומנט של מחרוזת && ((מחרוזת)) ארגומנט. בטל appendTo (חיץ StringBuffer) {// NOOP}}); החזר אפס; }

8.3. JMockit

התאמת ארגומנטים בהתאמה אישית עם JMockit נעשית עם הספיישל withArgThat (התאמה) שיטה (המקבלת את המקרסט שידוך חפצים).

@Test בטל פומבי @Matching () {UserForm userForm = UserForm חדש (); userForm.username = "foo"; // התאמת ברירת מחדל חדשה ציפיות () {{loginService.login ((UserForm) כל); תוצאה = נכון; // login matcher complexService.setCurrentUser (withArgThat (BaseMatcher חדש () {@Override התאמות בוליאניות ציבוריות (פריט אובייקט) {מופע פריט חוזר של String && ((String) item) .startsWith ("foo");} @Override public public ריק לתאר (תיאור תיאור) {// NOOP}})); }}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); FullVerifications חדשים (loginService) {}; }

9. ללעג חלקי

9.1. מוקיטו

Mockito מאפשר לגלוג חלקי (דמה המשתמשת ביישום האמיתי במקום קריאות בשיטה מדומה בחלק מהשיטות שלו) בשתי דרכים.

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

@Test ציבורי בטל partialMocking () {// השתמש loginController חלקי מדומה.loginService = spiedLoginService; UserForm userForm = משתמש חדש (); userForm.username = "foo"; // תן לכניסה של השירות להשתמש ביישום אז בואו ללעוג ל- DAO להתקשר ל- Mockito.when (loginDao.login (userForm)). ואז להחזיר (1); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); // אמת שיחה לעגה Mockito.verify (spiedLoginService) .setCurrentUser ("foo"); }

9.2. EasyMock

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

זה נעשה עם EasyMock.partialMockBuilder (Class.class) .addMockedMethod ("methodName"). CreateMock (). לאחר שהדבר נעשה, תוכלו להשתמש בלעג כמו בכל דמה שאינה חלקית אחרת.

@Test ציבורי בטל partialMocking () {UserForm userForm = UserForm חדש (); userForm.username = "foo"; / / השתמש ב- LoginService loginServicePartial = EasyMock.partialMockBuilder (LoginService.class) .addMockedMethod ("setCurrentUser"). createMock (); loginServicePartial.setCurrentUser ("foo"); // תן לכניסה של השירות להשתמש ביישום אז בואו ללעוג ל- DAO להתקשר אל EasyMock.expect (loginDao.login (userForm)). andReturn (1); loginServicePartial.setLoginDao (loginDao); loginController.loginService = loginServicePartial; EasyMock.replay (loginDao); EasyMock.replay (loginServicePartial); כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); // אמת את השיחה הלעוגה EasyMock.verify (loginServicePartial); EasyMock.verify (loginDao); }

9.3. JMockit

לגלוג חלקי עם JMockit קל במיוחד. כל קריאת שיטה שלגביה לא הוגדרה התנהגות לעגית ב- ציפיות(){{}} שימושים היישום "האמיתי".

עכשיו בואו נדמיין שאנחנו רוצים ללעוג חלקית ל LoginService בכיתה ללעוג ל setCurrentUser () תוך שימוש ביישום בפועל של התחברות() שיטה.

לשם כך, ראשית אנו יוצרים ומעבירים מופע של LoginService לגוש הציפיות. לאחר מכן, אנו רק רושמים ציפייה ל setCurrentUser () שיטה:

@Test ציבורי בטל partialMocking () {LoginService partialLoginService = שירות כניסה חדש (); partialLoginService.setLoginDao (loginDao); loginController.loginService = partialLoginService; UserForm userForm = משתמש חדש (); userForm.username = "foo"; ציפיות חדשות (partialLoginService) {{// בואו ללעוג ל- DAO להתקשר ל- loginDao.login (userForm); תוצאה = 1; // אין ציפייה לשיטת הכניסה כך שישתמש בהטמעה אמיתית // מדומה setCurrentUser קוראים partialLoginService.setCurrentUser ("foo"); }}; כניסה למחרוזת = loginController.login (userForm); Assert.assertEquals ("אישור", כניסה); // אמת שיחה לעגה אימות חדש () {{partialLoginService.setCurrentUser ("foo"); }}; }

10. מסקנה

בפוסט זה השווינו שלוש ספריות מדומה של Java, שלכל אחת מהן נקודות החסרון והחסרונות שלה.

  • שלושתם מוגדר בקלות עם הערות שיעזרו לך להגדיר לעגים ואת האובייקט הנבדק, עם רצים כדי להפוך הזרקת מדומה לכאובה ככל האפשר.
    • היינו אומרים שמוקיטו ינצח כאן מכיוון שיש לה הערה מיוחדת ללעג חלקי, אבל JMockit אפילו לא צריך את זה, אז בואו נגיד שזה שוויון בין שני אלה.
  • שלושתם עוקבים פחות או יותר אחרי דפוס שיא-חזרה, אך לדעתנו, הטוב ביותר לעשות זאת הוא JMockit מכיוון שהוא מכריח אותך להשתמש בבלוקים, כך שהמבחנים יהיו מובנים יותר.
  • קַלוּת השימוש חשוב, כך שתוכלו לעבוד כמה שפחות על מנת להגדיר את הבדיקות שלכם. JMockit תהיה האפשרות שנבחרה עבור המבנה הקבוע תמיד-אותו-דבר.
  • Mockito הוא פחות או יותר הידוע ביותר כך קהילה יהיה גדול יותר.
  • צריך להתקשר שידור חוזר כל פעם שאתה רוצה להשתמש במד הוא ברור לא ללכתאז נכניס מינוס אחד ל- EasyMock.
  • עקביות / פשטות חשוב לי גם. אהבנו את הדרך להחזיר תוצאות של JMockit זהה לתוצאות "רגילות" כמו לחריגים.

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

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


$config[zx-auto] not found$config[zx-overlay] not found