- בדיקת אינטגרציה של מסד נתונים באמצעות MariaDB להחלפת MySql
- יישום יישום רב לשוני
- שמירת קבצים באפליקציה ונתונים עליהם במסד הנתונים
סוגי בדיקות
מה זה מבחן? כפי שאומר ויקי: " מבחן או מבחן הם דרך לחקור את התהליכים הבסיסיים של מערכת על ידי הצבת המערכת במצבים שונים ומעקב אחר שינויים נצפים בה." במילים אחרות, זהו בדיקה של הפעולה הנכונה של המערכת שלנו במצבים מסוימים. ובכן, בוא נראה אילו סוגי בדיקות יש:-
בדיקת יחידה היא בדיקות שתפקידן לבדוק כל מודול של המערכת בנפרד. רצוי שאלו חלקים של המערכת הניתנים לחלוקה מינימלית, למשל מודולים.
-
בדיקת מערכת היא בדיקה ברמה גבוהה לבדיקת הפעולה של חלק גדול יותר של אפליקציה או של המערכת כולה.
-
בדיקת רגרסיה היא בדיקה המשמשת כדי לבדוק האם תכונות חדשות או תיקוני באגים משפיעים על הפונקציונליות הקיימת של האפליקציה והאם באגים ישנים מופיעים שוב.
-
בדיקה פונקציונלית היא בדיקת תאימות של חלק מהאפליקציה לדרישות המצוינות במפרטים, בסיפורי משתמשים וכו'.
סוגי בדיקות תפקודיות:
- בדיקת "קופסה לבנה" לעמידה של חלק מהאפליקציה בדרישות תוך הכרת היישום הפנימי של המערכת;
- בדיקת "קופסה שחורה" לעמידה של חלק מהאפליקציה בדרישות ללא ידיעה על היישום הפנימי של המערכת.
- בדיקת ביצועים היא סוג של בדיקות שנכתבות כדי לקבוע את המהירות שבה מערכת או חלק ממנה פועלים בעומס מסוים.
- בדיקת עומסים - בדיקות שנועדו לבדוק את יציבות המערכת בעומסים סטנדרטיים ולמצוא את השיא המקסימלי האפשרי בו האפליקציה פועלת בצורה נכונה.
- בדיקת מאמץ היא סוג של בדיקה שנועדה לבדוק את הפונקציונליות של אפליקציה בעומסים לא סטנדרטיים ולקבוע את השיא המקסימלי האפשרי שבו המערכת לא תתרסק.
- בדיקות אבטחה - בדיקות המשמשות לבדיקת אבטחת מערכת (מהתקפות של האקרים, וירוסים, גישה לא מורשית לנתונים חסויים ועוד הנאות חיים).
- בדיקת לוקליזציה היא בדיקת לוקליזציה עבור אפליקציה.
- בדיקת שמישות היא סוג של בדיקה שמטרתה לבדוק שימושיות, מובנות, אטרקטיביות ויכולת למידה עבור המשתמשים. כל זה נשמע טוב, אבל איך זה עובד בפועל? זה פשוט: נעשה שימוש בפירמידת הבדיקה של מייק קון: זוהי גרסה פשוטה של הפירמידה: כעת היא מחולקת לחלקים קטנים יותר. אבל היום לא נסוות ונשקול את האפשרות הפשוטה ביותר.
-
Unit - בדיקות יחידה המשמשות בשכבות שונות של האפליקציה, בודקות את ההיגיון הניתן לחלוקה הקטן ביותר של האפליקציה: למשל, מחלקה, אך לרוב שיטה. בדיקות אלו מנסות בדרך כלל לבודד כמה שניתן מהיגיון חיצוני, כלומר ליצור אשליה ששאר האפליקציה עובדת במצב סטנדרטי.
תמיד צריכות להיות הרבה בדיקות אלו (יותר מסוגים אחרים), מכיוון שהן בודקות חתיכות קטנות והן מאוד קלות משקל, לא צורכות הרבה משאבים (במשאבים אני מתכוון ל-RAM וזמן).
-
אינטגרציה - בדיקת אינטגרציה. זה בודק חלקים גדולים יותר של המערכת, כלומר, זה או שילוב של כמה חלקים של לוגיקה (כמה שיטות או מחלקות), או את נכונות העבודה עם רכיב חיצוני. בדרך כלל יש פחות מבדיקות אלו מאשר בדיקות יחידה, מכיוון שהן כבדות יותר.
כדוגמה למבחני אינטגרציה, אתה יכול לשקול להתחבר למסד נתונים ולבדוק את הביצוע הנכון של השיטות שעובדות איתו .
-
UI - בדיקות הבודקות את פעולת ממשק המשתמש. הם משפיעים על ההיגיון בכל רמות האפליקציה, ולכן הם נקראים גם מקצה לקצה. ככלל, יש הרבה פחות מהם, מכיוון שהם בעלי המשקל הכבד ביותר וחייבים לבדוק את הנתיבים הנחוצים ביותר (המשומשים).
באיור לעיל אנו רואים את היחס בין השטחים של חלקים שונים של המשולש: בערך אותו פרופורציה נשמר במספר המבחנים הללו בעבודה אמיתית.
היום נסתכל מקרוב על המבחנים הנפוצים ביותר - בדיקות יחידות, שכן כל מפתחי Java שמכבדים את עצמם צריכים להיות מסוגלים להשתמש בהם ברמה בסיסית.
- חומר על כיסוי קוד ב- JavaRush וב- Habré ;
- תורת הבדיקות הבסיסית .
- אנחנו כותבים את המבחן שלנו.
- אנחנו מריצים את המבחן, בין אם הוא עבר ובין אם לא (אנחנו רואים שהכל אדום - אל תתחרפן: ככה זה צריך להיות).
- אנו מוסיפים את הקוד שאמור לעמוד בבדיקה זו (הפעל את הבדיקה).
- אנחנו מחדשים את הקוד.
- ציון הנתונים לבדיקה (מתקנים).
- שימוש בקוד הנבדק (קורא לשיטה הנבדקת).
- בדיקת התוצאות והשוואתן לאלו הצפויות.
assertEquals(Object expecteds, Object actuals)
- בודק אם האובייקטים המועברים שווים.assertTrue(boolean flag)
- בודק אם הערך שעבר מחזיר אמת.assertFalse(boolean flag)
- בודק אם הערך שעבר מחזיר false.assertNull(Object object)
– בודק אם האובייקט הוא null.assertSame(Object firstObject, Object secondObject)
- בודק אם הערכים שעברו מתייחסים לאותו אובייקט.assertThat(T t, Matcher<T> matcher)
- בודק אם t עומד בתנאי שצוין בהתאמה.
מושגי מפתח של בדיקת יחידות
כיסוי מבחן (Code Coverage) הוא אחת ההערכות העיקריות של איכות בדיקת היישום. זהו אחוז הקוד שכוסה בבדיקות (0-100%). בפועל, הרבה אנשים רודפים אחרי האחוז הזה, שאני לא מסכים איתו, מאחר שמתחילים להוסיף מבחנים איפה שאין בהם צורך. לדוגמה, לשירות שלנו יש פעולות CRUD (יצירת/קבל/עדכן/מחק) סטנדרטיות ללא היגיון נוסף. שיטות אלו הן מתווכים גרידא המאצילים עבודה לשכבה שעובדת עם המאגר. במצב זה, אין לנו מה לבדוק: אולי אם השיטה הזו קוראת לשיטה מהטאו, אבל זה לא רציני. כדי להעריך את כיסוי הבדיקה, משתמשים בדרך כלל בכלים נוספים: JaCoCo, Cobertura, Clover, Emma וכו'. למחקר מפורט יותר של סוגיה זו, שמור כמה מאמרים מתאימים:שלבי בדיקה
המבחן מורכב משלושה שלבים:סביבות בדיקה
אז עכשיו בואו ניגש לעניינים. קיימות מספר סביבות בדיקה (מסגרות) זמינות עבור Java. הפופולריים שבהם הם JUnit ו-TestNG. לסקירה שלנו, אנו משתמשים: מבחן JUnit הוא שיטה הכלולה במחלקה המשמשת רק לבדיקה. מחלקה נקראת בדרך כלל זהה למחלקה שהיא בודקת עם +Test בסוף. לדוגמה, CarService → CarServiceTest. מערכת הבנייה של Maven כוללת באופן אוטומטי שיעורים כאלה באזור הבדיקה. למעשה, מחלקה זו נקראת כיתת מבחן. נעבור מעט על ההערות הבסיסיות: @Test - הגדרה של שיטה זו כשיטת בדיקה (למעשה, השיטה המסומנת בהערה זו היא מבחן יחידה). @Before - מסמן את השיטה שתתבצע לפני כל בדיקה. למשל, מילוי נתוני מבחן מחלקה, קריאת נתוני קלט וכו'. @After - ממוקם מעל השיטה שתיקרא לאחר כל מבחן (ניקוי נתונים, שחזור ערכי ברירת מחדל). @BeforeClass - ממוקם מעל השיטה - אנלוגי ל-@Before. אבל שיטה זו נקראת פעם אחת בלבד לפני כל המבחנים עבור מחלקה נתונה ולכן חייבת להיות סטטית. הוא משמש לביצוע פעולות כבדות יותר, כגון הרמת מסד נתונים בדיקה. @AfterClass הוא ההפך מ-@BeforeClass: מבוצע פעם אחת עבור מחלקה נתונה, אך מבוצע לאחר כל הבדיקות. משמש, למשל, לניקוי משאבים קבועים או ניתוק ממסד הנתונים. @התעלם - מציין שהשיטה למטה מושבתת ותתעלם ממנה בעת הפעלת בדיקות באופן כללי. הוא משמש במקרים שונים, למשל, אם שונתה שיטת הבסיס ולא היה זמן לבצע מחדש את הבדיקה עבורה. במקרים כאלה, רצוי להוסיף גם תיאור - @Ignore("Some description"). @Test (צפוי = Exception.class) - משמש לבדיקות שליליות. אלו בדיקות שבודקות כיצד מתנהגת שיטה במקרה של שגיאה, כלומר, הבדיקה מצפה שהשיטה תזרוק חריגה כלשהי. שיטה כזו מסומנת על ידי הערת @Test, אבל עם שגיאה לתפוס. @Test(timeout=100) - בודק שהשיטה מבוצעת תוך לא יותר מ-100 אלפיות שניות. @Mock - מחלקה משמשת מעל שדה כדי להגדיר אובייקט נתון כ-mock (זה לא מספריית Junit, אלא מ-Mockito), ואם אנחנו צריכים את זה, נגדיר את ההתנהגות של ה-mock במצב ספציפי , ישירות בשיטת הבדיקה. @RunWith(MockitoJUnitRunner.class) - השיטה ממוקמת מעל המחלקה. זה הכפתור להפעלת בדיקות בו. הרצים יכולים להיות שונים: לדוגמה, יש את הדברים הבאים: MockitoJUnitRunner, JUnitPlatform, SpringRunner וכו'). ב-JUnit 5, ההערה @RunWith הוחלפה בהערת @ExtendWith החזקה יותר. בואו נסתכל על כמה שיטות להשוואת תוצאות:assertThat(firstObject).isEqualTo(secondObject)
כאן דיברתי על השיטות הבסיסיות, שכן השאר הן וריאציות שונות של האמור לעיל.
תרגול בדיקות
עכשיו בואו נסתכל על החומר לעיל באמצעות דוגמה ספציפית. נבדוק את השיטה לשירות - עדכון. לא נשקול את שכבת הדאו, מכיוון שהיא ברירת המחדל שלנו. בואו נוסיף התחלה למבחנים:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
אז, מחלקת השירות:
@Service
@RequiredArgsConstructor
public class RobotServiceImpl implements RobotService {
private final RobotDAO robotDAO;
@Override
public Robot update(Long id, Robot robot) {
Robot found = robotDAO.findById(id);
return robotDAO.update(Robot.builder()
.id(id)
.name(robot.getName() != null ? robot.getName() : found.getName())
.cpu(robot.getCpu() != null ? robot.getCpu() : found.getCpu())
.producer(robot.getProducer() != null ? robot.getProducer() : found.getProducer())
.build());
}
}
8 - משוך את האובייקט המעודכן ממסד הנתונים 9-14 - צור את האובייקט דרך ה-Builder, אם לאובייקט הנכנס יש שדה - הגדר אותו, אם לא - השאר את מה שיש במסד הנתונים ותראה את הבדיקה שלנו:
@RunWith(MockitoJUnitRunner.class)
public class RobotServiceImplTest {
@Mock
private RobotDAO robotDAO;
private RobotServiceImpl robotService;
private static Robot testRobot;
@BeforeClass
public static void prepareTestData() {
testRobot = Robot
.builder()
.id(123L)
.name("testRobotMolly")
.cpu("Intel Core i7-9700K")
.producer("China")
.build();
}
@Before
public void init() {
robotService = new RobotServiceImpl(robotDAO);
}
1 - הרץ 4 שלנו - לבודד את השירות משכבת ה-dao על ידי החלפת מדומה 11 - הגדר ישות בדיקה למחלקה (זו שבה נשתמש כאוגר בדיקה) 22 - הגדר אובייקט שירות אותו נבדוק
@Test
public void updateTest() {
when(robotDAO.findById(any(Long.class))).thenReturn(testRobot);
when(robotDAO.update(any(Robot.class))).then(returnsFirstArg());
Robot robotForUpdate = Robot
.builder()
.name("Vally")
.cpu("AMD Ryzen 7 2700X")
.build();
Robot resultRobot = robotService.update(123L, robotForUpdate);
assertNotNull(resultRobot);
assertSame(resultRobot.getId(),testRobot.getId());
assertThat(resultRobot.getName()).isEqualTo(robotForUpdate.getName());
assertTrue(resultRobot.getCpu().equals(robotForUpdate.getCpu()));
assertEquals(resultRobot.getProducer(),testRobot.getProducer());
}
כאן אנו רואים חלוקה ברורה של הבדיקה לשלושה חלקים: 3-9 - הגדרת מכשירי 11 - ביצוע החלק הנבדק 13-17 - בדיקת התוצאות פרטים נוספים: 3-4 - הגדרת ההתנהגות של moka dao 5 - הגדרת מופע שנעדכן על תקן 11 שלנו - השתמשו בשיטה וקחו את המופע המתקבל 13 - בדקו שהוא לא אפס 14 - בדקו את מזהה התוצאה ואת ארגומנטי המתודה שצוינו 15 - בדקו אם השם עודכן 16 - תראו בתוצאה של מעבד 17 - מכיוון שלא קבענו זאת בשדה מופע העדכון, זה אמור להישאר זהה, בוא נבדוק את זה. בואו להשיק: הבדיקה ירוקה, אפשר לנשוף)) אז בואו נסכם: בדיקה משפרת את איכות הקוד והופכת את תהליך הפיתוח לגמיש ואמין יותר. תארו לעצמכם כמה מאמץ נצטרך להשקיע בעת עיצוב מחדש של תוכנה עם מאות קבצי כיתה. ברגע שנכתבו מבחני יחידה לכל הכיתות הללו, נוכל לבצע מחדש בביטחון. והכי חשוב, זה עוזר לנו למצוא בקלות שגיאות במהלך הפיתוח. חבר'ה, זה הכל בשבילי היום: צרפו לייקים, כתבו תגובות)))
GO TO FULL VERSION