בדיקת שיעור מופשט עם JUnit

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

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

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

2. תלות Maven

נתחיל בתלות של Maven:

 org.junit.jupiter junit-jupiter-engine 5.1.0 test org.mockito mockito-core 2.8.9 test org.powermock powermock-module-junit4 1.7.4 test junit junit org.powermock powermock-api-mockito2 1.7.4 מבחן 

תוכל למצוא את הגרסאות העדכניות ביותר של ספריות אלה ב- Maven Central.

Powermock אינו נתמך באופן מלא עבור Junit5. גַם, powermock-module-junit4 משמש רק לדוגמא אחת המוצגת בסעיף 5.

3. שיטה עצמאית שאינה מופשטת

בואו ניקח בחשבון מקרה שיש לנו שיעור מופשט עם שיטה ציבורית שאינה מופשטת:

שיעור מופשט ציבורי תקצירעצמאי {תקציר ציבורי אינטראקטיבי Func (); public String defaultImpl () {return "DEFAULT-1"; }}

אנו רוצים לבדוק את השיטה defaultImpl (), ויש לנו שני פתרונות אפשריים - שימוש בכיתת בטון, או שימוש במוקיטו.

3.1. שימוש בשיעור בטון

צור מעמד בטון שמתארך תקציר עצמאי בכיתה, והשתמש בה לבדיקת השיטה:

מעמד ציבורי ConcreteImpl מרחיב את AbstractIndependent {@Override public int abstractFunc () {return 4; }}
@ מבחן הריק ציבורי שניתן NonAbstractMethod_whenConcreteImpl_testCorrectBehaviour () {ConcreteImpl conClass = ConcreteImpl new (); מחרוזת בפועל = conClass.defaultImpl (); assertEquals ("DEFAULT-1", בפועל); }

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

3.2. באמצעות מוקיטו

לחלופין, אנו יכולים להשתמש מוקיטו ליצור דמה:

@Test public void givenNonAbstractMethod_whenMockitoMock_testCorrectBehaviour () {AbstractIndependent absCls = Mockito.mock (AbstractIndependent.class, Mockito.CALLS_REAL_METHODS); assertEquals ("DEFAULT-1", absCls.defaultImpl ()); }

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

4. שיטה מופשטת הנקראת משיטה לא מופשטת

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

שיעור מופשט ציבורי AbstractMethodCalling {תקציר ציבורי מחרוזת מופשטת Func (); public String defaultImpl () {String res = abstractFunc (); להחזיר (res == null)? "ברירת מחדל": (res + "ברירת מחדל"); }}

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

@Test public void givenDefaultImpl_whenMockAbstractFunc_thenExpectedBehaviour () {AbstractMethodCalling cls = Mockito.mock (AbstractMethodCalling.class); Mockito.when (cls.abstractFunc ()) .thenReturn ("מופשט"); Mockito.doCallRealMethod (). When (cls) .defaultImpl (); assertEquals ("ברירת מחדל מופשטת", cls.defaultImpl ()); }

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

5. שיטה לא מופשטת עם חסימת בדיקה

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

עלינו לעקוף את שיטת הבדיקה החוסמת לפני בדיקת שיטת היעד:

מעמד מופשט ציבורי AbstractPrivateMethods {תקציר ציבורי int abstractFunc (); מחרוזת public defaultImpl () {return getCurrentDateTime () + "DEFAULT-1"; } מחרוזת פרטית getCurrentDateTime () {החזר LocalDateTime.now (). toString (); }}

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

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

במקום זאת, עלינו להשתמש ב- PowerMock (נשים לב שהדוגמה הזו פועלת רק עם JUnit 4 מכיוון שתמיכה בתלות זו אינה זמינה עבור JUnit 5):

@RunWith (PowerMockRunner.class) @PrepareForTest (AbstractPrivateMethods.class) מחלקה ציבורית AbstractPrivateMethodsUnitTest {@Test public void whenMockPrivateMethod_thenVerifyBehaviour () {AbstractPrivateMethods mockClass = PowerMockito.mock; PowerMockito.doCallRealMethod () .when (mockClass) .defaultImpl (); מחרוזת dateTime = LocalDateTime.now (). ToString (); PowerMockito.doReturn (dateTime) .when (mockClass, "getCurrentDateTime"); מחרוזת בפועל = mockClass.defaultImpl (); assertEquals (dateTime + "DEFAULT-1", בפועל); }}

סיביות חשובות בדוגמה זו:

  • @לרוץ עם מגדיר את PowerMock כרץ למבחן
  • @PrepareForTest (מחלקה) אומר ל- PowerMock להכין את הכיתה לעיבוד מאוחר יותר

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

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

6. שיטה לא מופשטת אשר ניגשת לשדות מופע

לשיעורים מופשטים ניתן ליישם מצב פנימי עם שדות כיתה. לערך השדות יכולה להיות השפעה משמעותית על השיטה שנבחנת.

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

אבל אם זה פרטי, עלינו להשתמש PowerMockito:

מעמד מופשט ציבורי AbstractInstanceFields {ספירת מידע מוגן; פעיל בוליאני פעיל = שקר; תקציר ציבורי אינטראקטיבי Func (); test String public String () {if (count> 5) {return "Overflow"; } לחזור פעיל? "נוסף": "חסום"; }}

הנה ה testFunc () השיטה משתמשת בשדות ברמת מופע לספור ו פָּעִיל לפני שהוא חוזר.

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

מצד שני, לבדוק את ההתנהגות עם הפרטי פָּעִיל שדה, שוב נצטרך להשתמש PowerMockito, וזה קופסה לבנה מעמד:

@Test הציבור בטל כאשרPowerMockitoAndActiveFieldTrue_thenCorrectBehaviour () {AbstractInstanceFields instClass = PowerMockito.mock (AbstractInstanceFields.class); PowerMockito.doCallRealMethod () .when (instClass) .testFunc (); Whitebox.setInternalState (instClass, "פעיל", נכון); assertEquals ("נוסף", instClass.testFunc ()); }

אנו יוצרים כיתת stub באמצעות PowerMockito.mock (), ואנחנו משתמשים קופסה לבנה מחלקה לשליטה במצב הפנימי של האובייקט.

הערך של פָּעִיל שדה שונה ל נָכוֹן.

7. מסקנה

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

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

קוד המקור המלא זמין ב- GitHub.


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