בדיקה במגף האביב

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

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

אם אתה חדש ב- Spring Boot, עיין במבוא שלנו ל- Spring Boot.

2. הגדרת פרויקט

היישום שנשתמש בו במאמר זה הוא ממשק API המספק כמה פעולות בסיסיות ב- עוֹבֵד מַשׁאָב. זוהי ארכיטקטורה שכבתית אופיינית - שיחת ה- API מעובדת מה- בקר ל שֵׁרוּת אל ה הַתמָדָה שִׁכבָה.

3. תלות Maven

ראשית נוסיף את תלות הבדיקה שלנו:

 org.springframework.boot spring-boot-starter-test test 2.2.6.RELEASE com.h2database h2 test 

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

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

4. בדיקת שילוב עם @ DataJpaTest

אנחנו הולכים לעבוד עם ישות בשם עוֹבֵד, שיש לו תְעוּדַת זֶהוּת ו שֵׁם כתכונותיו:

@Entity @Table (name = "person") שכבה ציבורית שכיר {@ Id @ GeneratedValue (אסטרטגיה = GenerationType.AUTO) פרטי מזהה ארוך; @Size (min = 3, max = 20) שם מחרוזת פרטי; // סטרים וקובעים סטנדרטיים, בונים}

והנה המאגר שלנו באמצעות Spring Data JPA:

ממשק ציבורי @ מאגר @ EmployeeRepository מרחיב את JpaRepository {עובד ציבורי findByName (שם מחרוזת); }

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

ראשית, בואו ניצור את השלד של כיתת הבדיקה שלנו:

@RunWith (SpringRunner.class) @DataJpaTest מחלקת הציבור EmployeeRepositoryIntegrationTest {@Autowired פרטי TestEntityManager entityManager; מאגר עובד עובד מאגר פרטי; // כתוב כאן מקרי מבחן}

@RunWith (SpringRunner.class) מספק גשר בין תכונות בדיקת Boot Boot לבין JUnit. בכל פעם שאנו משתמשים בתכונות בדיקת Spring Boot כלשהן במבחני JUnit שלנו, תידרש הערה זו.

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

  • קביעת תצורה של H2, בסיס נתונים בזיכרון
  • הגדרת מצב שינה, נתוני אביב ו מקור מידע
  • ביצוע @EntityScan
  • הפעלת רישום SQL

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

מגף האביב TestEntityManager מהווה אלטרנטיבה ל- JPA הרגיל EntityManager המספק שיטות נפוצות בעת כתיבת מבחנים.

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

עכשיו בואו נכתוב את מקרה הבדיקה הראשון שלנו:

@ מבחן ציבורי בטל כאשר FindByName_thenReturnEmployee () {// ניתן לעובד alex = עובד חדש ("אלכס"); entityManager.persist (אלכס); entityManager.flush (); // כאשר העובד מצא = workerRepository.findByName (alex.getName ()); // ואז assertThat (found.getName ()) .isEqualTo (alex.getName ()); }

במבחן הנ"ל אנו משתמשים ב- TestEntityManager להכניס עוֹבֵד ב- DB וקריאתו דרך ה- API לפי find by name.

ה טוען כי (...) החלק מגיע מספריית Assertj, שמגיעה יחד עם Spring Boot.

5. ללעוג עם @MockBean

שֶׁלָנוּ שֵׁרוּת קוד השכבה תלוי ב מאגר.

עם זאת, כדי לבדוק את שֵׁרוּת שכבה, איננו צריכים לדעת או לדאוג כיצד מיושמת שכבת ההתמדה:

המחלקה הציבורית @Service EmployeeServiceImpl מיישמת את EmployeeService {@ EmployeeSepository עובד עובד מאגר; @Override עובד ציבורי getEmployeeByName (שם מחרוזת) {החזר עובדRepository.findByName (שם); }}

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

כדי להשיג זאת, אנו יכולים להשתמש בתמיכת הלעג הניתנת על ידי Test Boot Boot.

בואו נסתכל תחילה על שלד כיתת הבדיקה:

@RunWith (SpringRunner.class) מחלקה ציבורית EmployeeServiceImplIntegrationTest {@TestConfiguration class static EmployeeServiceImplTestContextConfiguration {@Bean EmployeeService publicServiceService () {להחזיר EmployeeServiceImpl חדש (); }} @ EmployeeService עובד אישי פרטי; @MockBean עובד עובד במאגר עובדים מאגר; // כתוב כאן מקרי מבחן}

כדי לבדוק את שֵׁרוּת בכיתה, עלינו לקבל מופע של שֵׁרוּת הכיתה נוצרה וזמינה כ- @אפונה כדי שנוכל @Autowire זה בשיעור המבחנים שלנו. אנו יכולים להשיג תצורה זו באמצעות @TestConfiguration ביאור.

במהלך סריקת רכיבים, אנו עשויים לגלות שרכיבים או תצורות שנוצרו רק לבדיקות ספציפיות נקלטים בטעות בכל מקום. כדי למנוע זאת, מגף האביב מספק את @TestConfiguration ביאור שנוכל להוסיף לשיעורים ב src / test / java כדי לציין כי אסור להרים אותם באמצעות סריקה.

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

@ לפני setUp בטל פומבי () {עובד אלכס = עובד חדש ("אלכס"); Mockito.when (employeeRepository.findByName (alex.getName ())) .thenReturn (alex); }

מאחר שההתקנה הסתיימה, מקרה הבדיקה יהיה פשוט יותר:

@Test ציבורי בטל כאשר ValidName_thenEmployeeShouldBeFound () {שם מחרוזת = "אלכס"; עובד נמצא = employeeService.getEmployeeByName (שם); assertThat (found.getName ()) .isEqualTo (שם); }

6. בדיקת יחידה עם @WebMvcTest

שֶׁלָנוּ בקר תלוי ב שֵׁרוּת שִׁכבָה; בואו נכלול רק שיטה אחת לפשטות:

@RestController @RequestMapping ("/ api") מעמד ציבורי EmployERestController {@ שירות עובד שכיר פרטי של עובדים; @GetMapping ("/ עובדים") רשימה ציבורית getAllEmployees () {להחזיר employeeService.getAllEmployees (); }}

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

@RunWith (SpringRunner.class) @WebMvcTest (EmployeeRestController.class) מחלקה ציבורית EmployeeRestControllerIntegrationTest {@ MowMvc mvc פרטי פרטי שירות שירות עובדים פרטי של @MockBean; // כתוב כאן מקרי מבחן}

כדי לבדוק את בקרים, אנחנו יכולים להשתמש @WebMvcTest. זה יגדיר אוטומטית את תשתית ה- Spring MVC לבדיקות היחידות שלנו.

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

@WebMvcTest גם תצורות אוטומטיות MockMvc, המציעה דרך עוצמתית לבדיקה קלה של בקרי MVC מבלי להפעיל שרת HTTP מלא.

עם זאת, בואו נכתוב את מקרה הבדיקה שלנו:

@ מבחן בטל פומבי שניתן Employe_whenGetEmployees_thenReturnJsonArray () זורק חריג {עובד אלכס = עובד חדש ("אלכס"); רשום את כל העובדים = Arrays.asList (אלכס); given (service.getAllEmployees ()). willReturn (allEmployees); mvc.perform (get ("/ api / workers") .contentType (MediaType.APPLICATION_JSON)) .andExpect (status (). isOk ()). andExpect (jsonPath ("$", hasSize (1))). andExpect ( jsonPath ("$ [0] .name", הוא (alex.getName ()))); }

ה לקבל(…) ניתן להחליף את קריאת השיטה בשיטות אחרות המתאימות לפעלים של HTTP כמו לָשִׂים(), הודעה()וכו 'שים לב שאנו מגדירים את סוג התוכן בבקשה.

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

7. בדיקת שילוב עם @ SpringBootTest

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

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

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

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

@RunWith (SpringRunner.class) @SpringBootTest (SpringBootTest.WebEnvironment.MOCK, classes = Application.class) @AutoConfigureMockMvc @TestPropertySource (locations = "classpath: application-integrationtest.properties") מעמד ציבורי EmployeeRestController Mvc; @ מאגר פרטי לעובדים פרטיים אוטומטיים; // כתוב כאן מקרי מבחן}

ה @ SpringBootTest ביאור שימושי כשאנחנו צריכים לאתחל את כל המכולה. ההערה פועלת על ידי יצירת ה- ApplicationContext שישמש במבחנים שלנו.

אנחנו יכולים להשתמש ב- webEnvironment תכונה של @ SpringBootTest כדי להגדיר את סביבת זמן הריצה שלנו; אנחנו משתמשים WebEnvironment.MOCK כאן כדי שהמיכל יפעל בסביבת servlet מדומה.

לאחר מכן, @TestPropertySource ביאור מסייע בתצורת המיקומים של קבצי המאפיינים הספציפיים למבחנים שלנו. שים לב שקובץ המאפיינים נטען עם @TestPropertySource יעקוף את הקיים application.properties קוֹבֶץ.

ה יישומים- integrationtest.properties מכיל את הפרטים לתצורת אחסון ההתמדה:

spring.datasource.url = jdbc: h2: mem: test spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect

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

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

@Test הציבור בטל givenEmployees_whenGetEmployees_thenStatus200 () זורק Exception {createTestEmployee ("bob"); mvc.perform (get ("/ api / workers") .contentType (MediaType.APPLICATION_JSON)). andExpect (status (). isOk ()). andExpect (content () .contentTypeCompatibleWith (MediaType.APPLICATION_JSON)). and Exppect (jsonPath ("$ [0] .name", הוא ("bob"))); }

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

8. בדיקות מוגדרות אוטומטית

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

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

  • @WebFלוקסט: אנחנו יכולים להשתמש ב- @WebFluxTest ביאור לבדיקת בקרי SpringFlux. זה משמש לעתים קרובות יחד עם @MockBean לספק יישומים מדומים לתלות נדרשת.
  • @JdbcTest: Wאתה יכול להשתמש ב- @JdbcTest ביאור לבדיקת יישומי JPA, אך זה נועד לבדיקות שדורשות רק מקור מידע. ההערה מגדירה מסד נתונים משובץ בזיכרון ו- JdbcTemplate.
  • @JooqTest: כדי לבדוק בדיקות הקשורות ל- JOOQ, אנו יכולים להשתמש בהן @JooqTest ביאור, שמגדיר תצורה של DSLContext.
  • @ DataMongoTest: לבדיקת יישומי MongoDB, @ DataMongoTest הוא הערה שימושית. כברירת מחדל, הוא מגדיר MongoDB מוטבע בזיכרון אם מנהל ההתקן זמין באמצעות תלות, מגדיר MongoTemplate, סורק אחר @מסמך מחלקות, ומגדיר מאגרי Spring Data MongoDB.
  • @ DataRedisTestמקל על בדיקת יישומי Redis. זה סורק אחרי @ RedisHash מחלקות ומגדיר תצורה של מאגרי Spring Data Redis כברירת מחדל.
  • @ DataLdapTest מגדיר תצורה משובצת בזיכרון LDAP (אם זמין), מגדיר א LdapTemplate, סורק אחר @כְּנִיסָה שיעורים, ומגדיר את נתוני האביב LDAP מאגרים כברירת מחדל.
  • @ RestClientTest: בדרך כלל אנו משתמשים ב- @ RestClientTest ביאור לבדיקת לקוחות REST. זה מגדיר באופן אוטומטי תלות שונות כמו תמיכה בג'קסון, GSON ו- Jsonb; מגדיר א RestTemplateBuilder; ומוסיף תמיכה ב MockRestServiceServer כברירת מחדל.

9. מסקנה

במאמר זה, צללנו עמוק לתמיכה בבדיקות ב- Spring Boot והראינו כיצד לכתוב בדיקות יחידות בצורה יעילה.

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

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