בדיקת REST API עם מלפפון

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

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

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

2. גרגין - שפת המלפפון

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

2.1. מבוא לג'רקין

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

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

הנה דוגמה פשוטה למסמך של גרקין:

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

בחלקים הבאים נתאר כמה אלמנטים חשובים ביותר במבנה הג'רקין.

2.2. תכונה

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

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

2.3. תרחישים ושלבים

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

דברים אלה נעשים באמצעות שלבים, המזוהים על ידי אחת מחמש מילות המפתח: נָתוּן, מתי, לאחר מכן, וגם, ו אבל.

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

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

3. יישום מלפפון- JVM

מלפפון נכתב במקור ברובי והועבר לג'אווה עם יישום מלפפון JVM, וזה הנושא של סעיף זה.

3.1. תלות Maven

על מנת להשתמש ב- Cucumber-JVM בפרויקט Maven, יש לכלול את התלות הבאה ב- POM:

 מבחן מלפפון מלפפון-ג'אווה 6.8.0 

כדי להקל על בדיקת JUnit עם מלפפון, עלינו להיות תלות אחת נוספת:

 io. מלפפון מלפפון- Junit 6.8.0 

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

3.2. הגדרות שלב

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

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

בהתחשב בכך שרשמתי קורס בבלדונג

והגדרת צעד:

@Given ("רשמתי קורס בבאלדונג") בטל ציבור VerifyAccount () {// יישום השיטה}

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

4. יצירה והפעלה של מבחנים

4.1. כתיבת קובץ תכונות

נתחיל בהכרזת תרחישים ושלבים בקובץ שהשם מסתיים ב- תכונה סיומת:

תכונה: בדיקת REST API על המשתמשים להיות מסוגלים להגיש בקשות GET ו- POST לשירות אינטרנט, המיוצג על ידי תרחיש WireMock: העלאת נתונים לשירות אינטרנט כאשר משתמשים מעלים נתונים בפרויקט ואז השרת צריך לטפל בזה ולהחזיר סטטוס הצלחה תרחיש: אחזור נתונים משירות אינטרנט כאשר משתמשים רוצים לקבל מידע על פרויקט 'מלפפון' אזי מוחזרים הנתונים המבוקשים

כעת אנו שומרים קובץ זה בספריה בשם תכונה, בתנאי שהספרייה תוטען לשביל הכיתה בזמן הריצה, למשל. src / main / resources.

4.2. קביעת תצורה של JUnit לעבודה עם מלפפון

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

@RunWith (Cucumber.class) @CucumberOptions (features = "classpath: Feature") מחלקה ציבורית CucumberIntegrationTest {}

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

4.3. הגדרות שלב כתיבה

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

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

להלן שיטה התואמת לחלוטין את שלב הג'רקין. השיטה תשמש לפרסום נתונים לשירות אינטרנט REST:

@When ("משתמשים מעלים נתונים על פרויקט") משתמשים מבטלים ציבורייםUploadDataOnAProject () זורק IOException {}

והנה שיטה המתאימה לשלב Gherkin ולוקחת טיעון מהטקסט, שישמש לקבלת מידע משירות רשת REST:

@When ("משתמשים רוצים לקבל מידע על הפרויקט {string}") משתמשי הריקודים הציבורייםGetInformationOnAProject (String projectName) זורק IOException {}

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

לחלופין, נוכל להשתמש בביטוי רגולרי:

@When ("^ משתמשים רוצים לקבל מידע על '(. +)' פרויקט $") משתמשים ריקים ציבורייםGetInformationOnAProject (שם מחרוזת) זורק IOException {}

שים לב, ה- ‘^' ו ‘$' אשר מציינים את תחילת וסוף ה- regex בהתאם. ואילו ‘(.+)' תואם את חוּט פָּרָמֶטֶר.

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

4.4. יצירה והפעלה של מבחנים

ראשית, נתחיל במבנה JSON כדי להמחיש את הנתונים שהועלו לשרת על ידי בקשת POST, והורדו ללקוח באמצעות GET. מבנה זה נשמר ב jsonString שדה, ומוצג להלן:

{"testing-framework": "מלפפון", "שפה נתמכת": ["Ruby", "Java", "Javascript", "PHP", "Python", "C ++"], "website": "מלפפון. io "}

כדי להדגים REST API, אנו משתמשים בשרת WireMock:

WireMockServer wireMockServer = WireMockServer חדש (אפשרויות (). DynamicPort ());

בנוסף נשתמש ב- Apache HttpClient API כדי לייצג את הלקוח המשמש להתחברות לשרת:

CloseableHttpClient httpClient = HttpClients.createDefault ();

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

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

wireMockServer.start ();

שימוש ב- WireMock API כדי לדחות את שירות REST:

configureFor ("localhost", wireMockServer.port ()); stubFor (post (urlEqualTo ("/ create")) .withHeader ("type-content", equalTo ("application / json")) .withRequestBody (המכיל ("framework-testing")) .willReturn (aResponse (). withStatus (200)));

כעת שלח בקשת POST עם התוכן שנלקח מה- jsonString שדה שהוכרז לעיל לשרת:

HttpPost בקשה = HttpPost חדש ("// localhost:" + wireMockServer.port () + "/ create"); ישות StringEntity = StringEntity חדש (jsonString); request.addHeader ("סוג תוכן", "יישום / json"); request.setEntity (ישות); תגובה HttpResponse = httpClient.execute (בקשה);

הקוד הבא מצהיר כי בקשת ה- POST התקבלה וטופלה בהצלחה:

assertEquals (200, response.getStatusLine (). getStatusCode ()); אמת (postRequestedFor (urlEqualTo ("/ create")) .withHeader ("type content", equalTo ("application / json")));

השרת אמור להפסיק לאחר השימוש בו:

wireMockServer.stop ();

השיטה השנייה שניישם כאן היא usersGetInformationOnAProject (שם מחרוזת). בדומה למבחן הראשון, עלינו להפעיל את השרת ואז לדלג את שירות ה- REST:

wireMockServer.start (); configureFor ("localhost", wireMockServer.port ()); stubFor (get (urlEqualTo ("/ projects / cucumber")) .withHeader ("accept", equalTo ("application / json")) .willReturn (aResponse (). withBody (jsonString)));

הגשת בקשת GET וקבלת תשובה:

HttpGet בקשה = HttpGet חדש ("// localhost:" + wireMockServer.port () + "/ projects /" + projectName.toLowerCase ()); request.addHeader ("קבל", "יישום / json"); HttpResponse httpResponse = httpClient.execute (בקשה);

אנו להמיר את http תגובה משתנה ל- a חוּט בשיטת עוזר:

מחרוזת responseString = convertResponseToString (httpResponse);

להלן יישום שיטת עוזר ההמרות ההיא:

מחרוזת פרטית convertResponseToString (תגובה HttpResponse) זורק IOException {InputStream responseStream = respons.getEntity (). getContent (); סורק סורק = סורק חדש (responseStream, "UTF-8"); מחרוזת responseString = scanner.useDelimiter ("\ Z"). הבא (); scanner.close (); תגובה תגובה מחרוזת; }

הדברים הבאים מאמתים את כל התהליך:

assertThat (responseString, containString ("\" testing-framework \ ": \" מלפפון \ "")); assertThat (responseString, containString ("\" אתר \ ": \" cucumber.io \ "")); אמת (getRequestedFor (urlEqualTo ("/ פרויקטים / מלפפון")). withHeader ("accept", equalTo ("application / json")));

לבסוף, עצור את השרת כמתואר קודם.

5. תכונות ריצה במקביל

מלפפון-JVM תומך באופן מקורי בביצוע בדיקות מקביליות על פני מספר נושאים. נשתמש ב- JUnit יחד עם תוסף Maven Failsafe לביצוע הרצים. לחלופין, נוכל להשתמש ב- Maven Surefire.

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

בואו כעת נוסיף את תצורת התוסף:

 maven-failsafe-plugin $ {maven-failsafe-plugin.version} שיטות CucumberIntegrationTest.java 2 בדיקת שילוב-בדיקה 

ציין זאת:

  • מַקְבִּיל: יכול להיות שיעורים, שיטות, או שניהם - במקרה שלנו, שיעורים יגרום לכל כיתת מבחן לרוץ בשרשור נפרד
  • threadCount: מציין כמה שרשורים יש להקצות לביצוע זה

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

6. מסקנה

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

כרגיל, כל דגימות הקוד המוצגות במדריך זה זמינות ב- GitHub.