בדיקת אינטגרציה באביב

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

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

במאמר זה נראה כיצד נוכל למנף את מסגרת הבדיקה של Spring MVC על מנת לכתוב ולהריץ מבחני אינטגרציה הבודקים בקרים מבלי להתחיל במפורש מיכל Servlet.

2. הכנה

התלות הבאות של Maven נדרשות להפעלת מבחני שילוב כמתואר במאמר זה. בראש ובראשונה התלות האחרונה במבחן JUnit ו- Spring:

 junit junit 4.12 test org.springframework spring-test 4.3.2. מבחן שחרור 

לצורך קביעת תוצאות אפקטיביות, נשתמש גם בנתיב Hamcrest ו- JSON:

 org.hamcrest hamcrest-library 1.3 test com.jayway.jsonpath json-path 2.2.0 test 

3. תצורת בדיקת MVC באביב

בואו כעת נציג כיצד להגדיר ולהפעיל את הבדיקות המאפשרות Spring.

3.1. אפשר אביב במבחנים

ראשית, כל מבחן מאופשר באביב יפעל בעזרת @RunWith (SpringJUnit4ClassRunner.class); הרץ הוא למעשה נקודת הכניסה להתחיל להשתמש במסגרת מבחן האביב.

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

בוא נראה:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (class = {ApplicationConfig.class}) @WebAppConfiguration בכיתה ציבורית GreetControllerIntegrationTest {....}

שימו לב איך, ב @ContextConfiguration, סיפקנו את ApplicationConfig.class מחלקת תצורה אשר טוענת את התצורה הדרושה לנו לבדיקה ספציפית זו.

השתמשנו בכיתת תצורה של Java כאן כדי לציין את תצורת ההקשר; באופן דומה, אנו יכולים להשתמש בתצורה מבוססת XML:

@ContextConfiguration (locations = {""})

לבסוף - גם המבחן מצוין עם @תצורת WebAppConfiguration - אשר יטען את הקשר יישומי האינטרנט.

כברירת מחדל, הוא מחפש את יישום האינטרנט הבסיסי בנתיב ברירת המחדל src / main / webapp; ניתן לבטל את המיקום על ידי העברת ה- ערך תכונה כ:

@WebAppConfiguration (value = "")

3.2. ה WebApplicationContext לְהִתְנַגֵד

WebApplicationContext (wac) מספק תצורת יישום אינטרנט. הוא מעמיס את כל פולי הבקרה והבקרים בהקשר.

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

@Autowired פרטי WebApplicationContext wac;

3.3. שעועית הקשר הלוגני

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

בואו נראה איך להשתמש בזה:

פרטי MockMvc mockMvc; @ לפני התקנת הריק הציבורי () זורק חריג {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .build (); }

עלינו לאתחל את mockMvc חפץ ב @לפני שיטת הערה, כך שלא נצטרך לאתחל אותה בכל בדיקה.

3.4. אמת את תצורת הבדיקה

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

@Test הציבור בטל givenWac_whenServletContext_thenItProvidesGreetController () {ServletContext servletContext = wac.getServletContext (); Assert.assertNotNull (servletContext); Assert.assertTrue (מופע servletContext של MockServletContext); Assert.assertNotNull (wac.getBean ("greetController")); }

שימו לב שאנחנו גם בודקים שאנחנו א GreetController.java שעועית קיימת בהקשר האינטרנטי - מה שמבטיח שעועית קפיץ נטענת כהלכה.

בשלב זה, ההתקנה של מבחן האינטגרציה נעשית. בואו נראה כיצד נוכל לבדוק שיטות משאבים באמצעות ה- MockMvc לְהִתְנַגֵד.

4. כתיבת מבחני שילוב

בחלק זה נעבור על הפעולות הבסיסיות הזמינות במסגרת הבדיקה.

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

הקטעים הבאים משתמשים בייבוא ​​סטטי מ- MockMvcRequestBuilders אוֹ MockMvcResultMatchers שיעורים.

4.1. אמת את שם התצוגה

בואו נקרא את /דף הבית נקודת קצה מהבדיקה שלנו כ:

// localhost: 8080 / אביב-mvc-test /

אוֹ

// localhost: 8080 / spring-mvc-test / homePage

קטע קוד:

@ מבחן בטל פומבי givenHomePageURI_whenMockMVC_thenReturnsIndexJSPViewName () {this.mockMvc.perform (get ("/ homePage")). AndDo (print ()). AndExpect (view (). Name ("index")); }

בואו נשבור את זה:

  • לְבַצֵעַ() השיטה תקרא לשיטת קבל בקשה המחזירה את תוצאות פעולות. באמצעות תוצאה זו נוכל לקבל ציפיות קביעה לגבי תגובה כמו תוכן, מצב HTTP, כותרת וכו '
  • andDo (הדפס ()) ידפיס את הבקשה והתגובה. זה מועיל לקבלת תצוגה מפורטת במקרה של שגיאה
  • ו- Expect ()יצפה לוויכוח שסופק. במקרה שלנו אנו מצפים כי "אינדקס" יוחזר באמצעות MockMvcResultMatchers.view ()

4.2. אמת את גוף התגובה

נפעיל /לברך נקודת סיום מהבדיקה שלנו כ:

// localhost: 8080 / spring-mvc-test / greet

תפוקה צפויה:

{"id": 1, "message": "שלום עולם !!!" }

קטע קוד:

@Test ציבורי בטל givenGreetURI_whenMockMVC_thenVerifyResponse () {MvcResult mvcResult = this.mockMvc.perform (get ("/ greet")). AndDo (print ()). AndExpect (status (). IsOk ()) .andExpect (jsonPath ("$) .message "). ערך (" שלום עולם !!! ")). וחזור (); Assert.assertEquals ("application / json; charset = UTF-8", mvcResult.getResponse (). GetContentType ()); }

בואו נראה בדיוק מה קורה:

  • andExpect (MockMvcResultMatchers.status (). isOk ())יאמת שמצב HTTP הוא התגובה בסדר כְּלוֹמַר 200. זה מבטיח שהבקשה בוצעה בהצלחה
  • ו- Expect (MockMvcResultMatchers.jsonPath ("$. הודעה"). ערך ("שלום עולם !!!")) יוודא שתוכן התגובה תואם את הטיעון "שלום עולם!!!". כאן השתמשנו jsonPath שמפיק תוכן תגובה ומספק את הערך המבוקש
  • ותחזור()יחזיר את MvcResult אובייקט המשמש אותנו כאשר עלינו לאמת דבר שאינו בר השגה על ידי הספרייה. אתה יכול לראות שהוספנו assertEquals כדי להתאים לסוג התוכן של התגובה שחולץ מה- MvcResult לְהִתְנַגֵד

4.3. שלח לקבל בקשה עם משתנה נתיב

נפעיל / greetWithPathVariable / {name} נקודת סיום מהבדיקה שלנו כ:

// localhost: 8080 / spring-mvc-test / greetWithPathVariable / John

תפוקה צפויה:

{"id": 1, "message": "שלום עולם ג'ון !!!" }

קטע קוד:

@Test הציבור בטל שניתןGreetURIWithPathVariable_whenMockMVC_thenResponseOK () {this.mockMvc .perform (get ("/ greetWithPathVariable / {name}", "John")). AndDo (print ()). AndExpect (status (). IsOk ()). (content (). contentType ("application / json; charset = UTF-8")). andExpect (jsonPath ("$. message"). ערך ("שלום עולם ג'ון !!!")); }

MockMvcRequestBuilders.get (“/ greetWithPathVariable / {name}”, “John”) ישלח בקשה כ- “/ greetWithPathVariable / John“.

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

4.4. לִשְׁלוֹחַ לקבל בקשה עם פרמטרים של שאילתה

נפעיל / greetWithQueryVariable? name = {name} נקודת סיום מהבדיקה שלנו כ:

// localhost: 8080 / spring-mvc-test / greetWithQueryVariable? name = John% 20Doe

תפוקה צפויה:

{"id": 1, "message": "שלום עולם ג'ון דו !!!" }

קטע קוד:

@Test הציבור בטל givenGreetURIWithQueryParameter_whenMockMVC_thenResponseOK () {this.mockMvc.perform (get ("/ greetWithQueryVariable") .param ("name", "John Doe")). AndDo (print ()). And Expect (status () is. andExpect (content (). contentType ("application / json; charset = UTF-8")). andExpect (jsonPath ("$. message"). value ("Hello World John Doe !!!")); }

param ("שם", "ג'ון דו") יוסיף את פרמטר השאילתה ב- לקבל בַּקָשָׁה. זה דומה ל " / greetWithQueryVariable? name = John% 20Doe“.

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

this.mockMvc.perform (get ("/ greetWithQueryVariable? name = {name}", "John Doe"));

4.5. לִשְׁלוֹחַ הודעה בַּקָשָׁה

נפעיל / greetWithPost נקודת סיום מהבדיקה שלנו כ:

// localhost: 8080 / spring-mvc-test / greetWithPost

תפוקה צפויה:

{"id": 1, "message": "שלום עולם !!!" }

קטע קוד:

@Test הציבור בטל givenGreetURIWithPost_whenMockMVC_thenVerifyResponse () {this.mockMvc.perform (post ("/ greetWithPost")). ועשה (הדפס ()). ו- Expect (סטטוס (). IsOk ()). וציפוי (תוכן () .contentType (" application / json; charset = UTF-8 ")). andExpect (jsonPath (" $. message "). value (" שלום עולם !!! ")); }

MockMvcRequestBuilders.post (“/ greetWithPost”) ישלח את בקשת ההודעה. ניתן להגדיר משתני נתיב ופרמטרים של שאילתה באופן דומה שנראה קודם לכן, בעוד שניתן להגדיר נתוני טופס באמצעות param () שיטה דומה רק לפרמטר שאילתה כ:

// localhost: 8080 / spring-mvc-test / greetWithPostAndFormData

טופס מידע:

id = 1; שם = John% 20Doe

תפוקה צפויה:

{"id": 1, "message": "שלום עולם ג'ון דו !!!" }

קטע קוד:

@ מבחן בטל פומבי givenGreetURIWithPostAndFormData_whenMockMVC_thenResponseOK () {this.mockMvc.perform (post ("/ greetWithPostAndFormData"). Param ("id", "1") .param ("name", "John Doe")) andDo (print). andExpect (status (). isOk ()). andExpect (content (). contentType ("application / json; charset = UTF-8")). andExpect (jsonPath ("$. message"). value (" שלום עולם ג'ון דו !!! ")). ו- Expect (jsonPath (" $. Id "). ערך (1)); }

בקטע הקוד שלעיל הוספנו שני פרמטרים מזהים כ- "1" ושם "ג'ון דו".

5. MockMvc מגבלות

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

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

ה MockMvc הכיתה עוטפת את זה TestDispatcherServlet כְּלַפֵּי פְּנִים. לכן, בכל פעם שאנחנו שולחים בקשה באמצעות לְבַצֵעַ() שיטה, MockMvc ישתמש בבסיס TestDispatcherServlet באופן ישיר. לָכֵן, אין חיבורי רשת אמיתיים, וכתוצאה מכך לא נבדוק את כל ערימת הרשת בזמן השימוש MockMvc.

גַם,מכיוון ש- Spring מכין הקשר מזויף של יישומי רשת ללעוג לבקשות ותגובות ה- HTTP, יתכן שהוא לא תומך בכל התכונות של יישום Spring מלא.

לדוגמה, הגדרת מדומה זו אינה תומכת בהפניות מחדש של HTTP. זה אולי לא נראה כל כך משמעותי בהתחלה. עם זאת, Spring Boot מטפל בכמה שגיאות על ידי הפניית הבקשה הנוכחית אל ה- /שְׁגִיאָה נקודת סיום. אז אם אנו משתמשים ב- MockMvc, ייתכן שלא נוכל לבדוק כמה כשלים ב- API.

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

למשל, זה קל באמצעות Spring Boot:

@RunWith (SpringRunner.class) @SpringBootTest (webEnvironment = RANDOM_PORT) מחלקה ציבורית GreetControllerRealIntegrationTest {@LocalServerPort int יציאה פרטית; @ לפני setUp הריק הציבורי () {RestAssured.port = יציאה; } @ מבחן חלל ציבורי givenGreetURI_whenSendingReq_thenVerifyResponse () {given (). Get ("/ greet") .then () .statusCode (200); }}

בדרך זו, כל בדיקה תגיש בקשת HTTP אמיתית ליישום שמאזין ביציאת TCP אקראית.

6. מסקנה

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

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

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

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

לבסוף, היישום של כל הדוגמאות וקטעי הקוד זמין ב- GitHub.