השוואה מהירה בין JUnit לעומת TestNG

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

JUnit ו- TestNG הן ללא ספק שתי המסגרות הפופולריות ביותר לבדיקת יחידות במערכת האקולוגית של ג'אווה. בעוד JUnit מעניק השראה ל- TestNG עצמה, הוא מספק את התכונות הייחודיות שלו, ובניגוד ל- JUnit, הוא פועל לרמות בדיקה פונקציונליות וגבוהות יותר.

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

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

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

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

מחלקה ציבורית SummationServiceTest {מספרי רשימה סטטית פרטית; @BeforeAll החלל הסטטי הציבורי מאותחל () {numbers = ArrayList חדש (); } @AfterAll חלל סטטי ציבורי tearDown () {numbers = null; } @ לפני כל רחב ציבורי runBeforeEachTest () {numbers.add (1); numbers.add (2); numbers.add (3); } @AfterEach ציבור ריק ריק runAfterEachTest () {numbers.clear (); } @Test ציבורי בטל givenNumbers_sumEquals_thenCorrect () {int sum = numbers.stream (). להפחית (0, שלם :: סכום); assertEquals (6, סכום); }}

שים לב כי דוגמה זו משתמשת ב- JUnit 5. בגרסת JUnit 4 הקודמת, נצטרך להשתמש ב- @לפני ו @לאחר ביאורים המקבילים ל- @ לפני כל אחד ו @אחרי כל אחד. כְּמוֹ כֵן, @ לפני כל ו @אחרי הכל הם תחליפים ל- JUnit 4 @לפני השיעור ו @אחרי השיעור.

בדומה ל- JUnit, TestNG מספק גם אתחול וניקוי ברמת השיטה והכיתה. בזמן @לפני השיעור ו @אחרי השיעור להישאר זהה ברמת הכיתה, ההערות ברמת השיטה הן @לפני מתודה ו @ AfterMethod:

@BeforeClass חלל ציבורי מאותחל () {numbers = ArrayList חדש (); } @AfterClass חלל ציבורי tearDown () {numbers = null; } @BeforeMethod בטל פומבי runBeforeEachTest () {numbers.add (1); numbers.add (2); numbers.add (3); } @AfterMethod בטל פומבי runAfterEachTest () {numbers.clear (); }

TestNG מציעה גם, @BeforeSuite, @AfterSuite, @BeforeGroup ו- @AfterGroup הערות, לתצורות ברמות החבילה והקבוצות:

@BeforeGroups ("positive_tests") חלל ציבורי runBeforeEachGroup () {numbers.add (1); numbers.add (2); numbers.add (3); } @AfterGroups ("negative_tests") חלל ציבורי runAfterEachGroup () {numbers.clear (); }

כמו כן, אנו יכולים להשתמש ב- @BeforeTest ו- @AfterTest אם אנו זקוקים לתצורה כלשהי לפני או אחרי מקרי הבדיקה הכלולים ב- תג בקובץ תצורה XML של TestNG:

שים לב כי ההצהרה על @לפני השיעור ו @אחרי השיעור השיטה צריכה להיות סטטית ב- JUnit. לשם השוואה, להצהרת שיטת TestNG אין מגבלות אלה.

3. התעלמות מבדיקות

שתי המסגרות תומכות בהתעלמות ממקרי המבחןלמרות שהם עושים את זה אחרת לגמרי. JUnit מציעה את @להתעלם ביאור:

@ Ignore @ Test public void givenNumbers_sumEquals_thenCorrect () {int sum = numbers.stream (). Reduce (0, Integer :: sum); Assert.assertEquals (6, סכום); }

ואילו TestNG משתמש @מִבְחָן עם פרמטר "מופעל" עם ערך בוליאני נָכוֹן אוֹ שֶׁקֶר:

@Test (מופעל = שקר) חלל ציבורי givenNumbers_sumEquals_thenCorrect () {int sum = numbers.stream.reduce (0, Integer :: sum); Assert.assertEquals (6, סכום); }

4. ריצת מבחנים ביחד

הפעלת מבחנים יחד כאוסף אפשרית בשניהם JUnit ו- TestNG, אך הם עושים זאת בדרכים שונות.

אנחנו יכולים להשתמש ב- @לרוץ עם,@SelectPackages, ו @SelectClasses ביאורים למקרי מבחן קבוצתיים והפעלתם כסוויטה יוניט 5. חבילה היא אוסף של מקרי מבחן שנוכל לקבץ יחד ולהריץ כמבחן יחיד.

אם אנו רוצים לקבץ מקרי בדיקה של חבילות שונות להפעלה יחדיו בתוך סְוִיטָה אנחנו צריכים את @SelectPackages ביאור:

@RunWith (JUnitPlatform.class) @SelectPackages ({"org.baeldung.java.suite.childpackage1", "org.baeldung.java.suite.childpackage2"}) מחלקה ציבורית SelectPackagesSuiteUnitTest {}

אם אנחנו רוצים שיעורי מבחן ספציפיים יפעלו יחד, יוניט 5 מספק את הגמישות באמצעות @SelectClasses:

@RunWith (JUnitPlatform.class) @SelectClasses ({Class1UnitTest.class, Class2UnitTest.class}) מחלקה ציבורית SelectClassesSuiteUnitTest {}

בעבר השתמש יוניט 4, השגנו קיבוץ והפעלת מספר מבחנים יחד באמצעות @סְוִיטָה ביאור:

@RunWith (Suite.class) @ Suite.SuiteClasses ({RegistrationTest.class, SignInTest.class}) SuiteTest בכיתה ציבורית {}

ב- TestNG אנו יכולים לקבץ בדיקות באמצעות קובץ XML:

זה מציין RegistrationTest ו SignInTest ירוצו יחד.

מלבד שיעורי קיבוץ, TestNG יכולה לקבץ שיטות גם באמצעות @מבחן (קבוצות = "groupName") ביאור:

@Test (קבוצות = "רגרסיה") חלל ציבורי נתון NegativeNumber_sumLessthanZero_thenCorrect () {int sum = numbers.stream (). להפחית (0, שלם :: סכום); Assert.assertTrue (סכום <0); }

בואו נשתמש ב- XML ​​לביצוע הקבוצות:

פעולה זו תבצע את שיטת הבדיקה שתויגה עם הקבוצה נְסִיגָה.

5. בדיקת חריגים

התכונה לבדיקת חריגים באמצעות הערות זמינה גם ב- JUnit וגם ב- TestNG.

בואו ניצור תחילה מחלקה בשיטה שמציגה חריג:

מחשבון מחלקה ציבורית {מחלק כפול ציבורי (כפול a, כפול ב) {אם (b == 0) {זרוק DivideByZeroException חדש ("מחלק לא יכול להיות שווה לאפס!"); } להחזיר את a / b; }}

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

@ מבחן ציבורי בטל כאשר DividerIsZero_thenDivideByZeroExceptionIsTrowne () {מחשבון מחשבון = מחשבון חדש (); assertThrows (DivideByZeroException.class, () -> calculator.divide (10, 0)); }

ב יוניט 4, אנו יכולים להשיג זאת באמצעות @Test (צפוי = DivideByZeroException.class) דרך ממשק ה- API לבדיקה.

ועם TestNG אנו יכולים גם ליישם את אותו הדבר:

@Test (expectExceptions = ArithmeticException.class) חלל ציבורי givenNumber_whenTrowsException_thenCorrect () {int i = 1/0; }

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

6. בדיקות פרמטריות

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

ב יוניט 5, יש לנו את היתרון בכך ששיטות בדיקה צורכות ארגומנטים של נתונים ישירות מהמקור שהוגדר. כברירת מחדל, JUnit 5 מספק כמה מָקוֹר ביאורים כמו:

  • @ValueSource: אנו יכולים להשתמש בזה עם מערך ערכים מסוג קצר, בת, Int, ארוך, Float, כפול, Char, ו חוּט:
@ParameterizedTest @ValueSource (מחרוזות = {"שלום", "עולם"}) בטל givenString_TestNullOrNot (מחרוזת) {assertNotNull (מילה); }
  • @EnumSource - עובר Enum קבועים כפרמטרים לשיטת הבדיקה:
@ParameterizedTest @EnumSource (value = PizzaDeliveryStrategy.class, names = {"EXPRESS", "NORMAL"}) void givenEnum_TestContainsOrNot (PizzaDeliveryStrategy timeUnit) {assertTrue (EnumSet.of (PizzaDeliveryStrategy.trategy. ; }
  • @MethodSource - עמ 'מעריך שיטות חיצוניות המפיקות זרמים:
סטטי סטרים wordDataProvider () {return Stream.of ("foo", "bar"); } @ParameterizedTest @MethodSource ("wordDataProvider") בטל givenMethodSource_TestInputStream (טיעון מחרוזת) {assertNotNull (טיעון); }
  • @CsvSource - משתמש בערכי CSV כמקור לפרמטרים:
@ParameterizedTest @CsvSource ({"1, רכב", "2, בית", "3, רכבת"}) בטל שניתן CSVSource_TestContent (מזהה int, מילה מחרוזת) {assertNotNull (id); assertNotNull (מילה); }

באופן דומה, יש לנו מקורות אחרים כמו @ CSVsvileSource אם עלינו לקרוא קובץ CSV מ- classpath ו- @ ארגומנטסורס כדי לציין מותאם אישית, לשימוש חוזר ספקי טיעונים.

ב יוניט 4, יש לציין את הכיתת הבדיקה @לרוץ עם כדי להפוך אותו למחלקה פרמטרית ו @פָּרָמֶטֶר כדי להשתמש בסימן ערכי הפרמטר לבדיקת יחידות.

ב- TestNG אנו יכולים לבצע פרמטריזציה של בדיקות באמצעות @פָּרָמֶטֶר אוֹ @ספק מידע ביאורים. תוך שימוש בקובץ ה- XML ​​הוסף הערה לשיטת הבדיקה באמצעות @פָּרָמֶטֶר:

@Test @Parameters ({"value", "isEven"}) חלל ציבורי givenNumberFromXML_ifEvenCheckOK_thenCorrect (ערך int, בוליאני isEven) {Assert.assertEquals (isEven, ערך% 2 == 0); }

ולספק את הנתונים בקובץ ה- XML:

השימוש במידע בקובץ ה- XML ​​הוא פשוט ושימושי, אך במקרים מסוימים ייתכן שיהיה עליך לספק נתונים מורכבים יותר.

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

הנה דוגמה לשימוש @ספק מידע לסוגי נתונים פרימיטיביים:

@ DataProvider (name = "numbers") אובייקט סטטי ציבורי [] [] evenNumbers () {להחזיר אובייקט חדש [] [] {{1, false}, {2, true}, {4, true}}; } @Test (dataProvider = "numbers") חלל ציבורי givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect (מספר שלם, צפוי בוליאני) {Assert.assertEquals (צפוי, מספר% 2 == 0); }

וגם @ספק מידע לחפצים:

@Test (dataProvider = "numbersObject") חלל ציבורי givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect (EvenNumber number) {Assert.assertEquals (number.isEven (), number.getValue ()% 2 == 0); } @ DataProvider (name = "numbersObject") אובייקט ציבורי [] [] parameterProvider () {להחזיר אובייקט חדש [] [] {{EvenNumber חדש (1, לא נכון)}, {חדש EvenNumber (2, נכון)}, {חדש EvenNumber (4, נכון)}}; }

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

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

7. פסק זמן למבחן

פירושו של פסק זמן של בדיקות, מקרה הבדיקה אמור להיכשל אם הביצוע לא הושלם בתוך פרק זמן מסוים. הן תמיכה ב- JUnit והן ב- TestNG תם זמן לבדיקות. ב יוניט 5 אנו יכולים לכתוב מבחן פסק זמן כ-:

@Test הציבור בטל שניתןExecution_takeMoreTime_thenFail () זורק InterruptedException {Assertions.assertTimeout (Duration.ofMillis (1000), () -> Thread.sleep (10000)); }

ב יוניט 4 ו- TestNG אנחנו יכולים לעשות את אותה בדיקה באמצעות @מבחן (פסק זמן = 1000)

@Test (timeOut = 1000) חלל ציבורי שניתןExecution_takeMoreTime_thenFail () {while (true); }

8. מבחנים תלויים

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

בואו נסתכל על תרחיש, בו עלינו לאמת דוא"ל, ואם הוא יצליח, נמשיך להתחבר:

@Test הציבור בטל givenEmail_ifValid_thenTrue () {בוליאני תקף = email.contains ("@"); Assert.assertEquals (תקף, נכון); } @Test (תלויOnMethods = {"givenEmail_ifValid_thenTrue"}) חלל ציבורי givenValidEmail_whenLoggedIn_thenTrue () {LOGGER.info ("דוא"ל {} תקף >> כניסה", דוא"ל); }

9. צו ביצוע מבחן

אין סדר מרומז מוגדר בו יבוצעו שיטות בדיקה ב- JUnit 4 או TestNG. השיטות פשוט מופעלות כפי שהוחזרו על ידי ממשק ה- API של השתקפות Java. מאז JUnit 4 הוא משתמש בסדר דטרמיניסטי יותר אך לא צפוי.

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

@FixMethodOrder (MethodSorters.NAME_ASCENDING) מחלקה ציבורית SortedTests {@Test public בטל a_givenString_whenChangedtoInt_thenTrue () {assertTrue (Integer.valueOf ("10") מופע של שלם); } @Test הציבור בטל b_givenInt_whenChangedtoString_thenTrue () {assertTrue (String.valueOf (10) instance of String); }}

ה MethodSorters.NAME_ASCENDING פרמטר ממיין את השיטות לפי שם השיטה הוא סדר לקסיקוגרפי. מלבד סדרן זה, יש לנו MethodSorter.DEFAULT ו- MethodSorter.JVM גם כן.

בעוד ש- TestNG מספקת גם כמה דרכים לקבל שליטה בסדר ביצוע שיטת הבדיקה. אנו מספקים את עדיפות פרמטר ב @מִבְחָן ביאור:

@Test (עדיפות = 1) חלל ציבורי givenString_whenChangedToInt_thenCorrect () {Assert.assertTrue (מופע שלם (Integer.valueOf ("10") של מספר שלם); } @Test (עדיפות = 2) חלל ציבורי givenInt_whenChangedToString_thenCorrect () {Assert.assertTrue (String.valueOf (23) instance of String); }

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

לפעמים בזמן כתיבת מקרי בדיקה פונקציונליים ב- TestNG, ייתכן שיהיה לנו מבחן תלוי זה בזה, שבו סדר הביצוע חייב להיות זהה לכל ריצת בדיקה. כדי להשיג זאת עלינו להשתמש ב תלוי OnMethods פרמטר ל- @מִבְחָן ביאור כפי שראינו בסעיף הקודם.

10. שם מבחן מותאם אישית

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

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

@ParameterizedTest @ValueSource (מחרוזות = {"שלום", "עולם"}) @DisplayName ("שיטת בדיקה כדי לבדוק שהקלטות אינן בטלות") בטל givenString_TestNullOrNot (מילת מחרוזת) {assertNotNull (מילה); }

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

כרגע, ב TestNG אין דרך לספק שם מותאם אישית.

11. מסקנה

גם JUnit וגם TestNG הם כלים מודרניים לבדיקה במערכת האקולוגית של Java.

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

את היישום של כל קטעי הקוד ניתן למצוא בפרויקט TestNG ו- junit-5 Github.