בדיקת REST API עם JBehave

1. מבוא

במאמר זה, נסתכל במהירות על JBehave, ואז נתמקד בבדיקת REST API מנקודת מבט של BDD.

2. JBehave ו- BDD

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

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

בדומה למסגרות BDD אחרות, JBehave מאמץ את המושגים הבאים:

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

תרחיש אופייני יהיה:

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

כל שלב בתרחיש תואם הערה ב- JBehave:

  • @נָתוּן: ליזום את ההקשר
  • @מתי: לעשות את הפעולה
  • @לאחר מכן: לבדוק את התוצאה הצפויה

3. תלות של Maven

כדי להשתמש ב- JBehave בפרויקט ה- maven שלנו, יש לכלול את התלות jbehave-core פום:

 org.jbehave מבחן jbehave-core 4.1 

4. דוגמה מהירה

כדי להשתמש ב- JBehave, עלינו לבצע את השלבים הבאים:

  1. כתוב סיפור משתמש
  2. מיפוי שלבים מסיפור המשתמש לקוד ג'אווה
  3. הגדר סיפורי משתמשים
  4. הפעל בדיקות JBehave
  5. סקור תוצאות

4.1. כַּתָבָה

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

אנחנו יכולים להגדיר את הסיפור ב- .כַּתָבָה קוֹבֶץ:

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

4.2. שלבי מיפוי

בהתחשב בשלבים, בואו יישם זאת ב- Java:

מעמד ציבורי IncreaseSteps {מונה אינטליגנטי פרטי; פרטית int previousValue; @Given ("מונה") פומבי בטל aCounter () {} @Given ("לדלפק יש ערך אינטגרלי כלשהו") counter counter voidHasAnyIntegralValue () {counter = new Random (). NextInt (); previousValue = מונה; } @ כאשר ("המשתמש מגדיל את הדלפק") הריק הציבורי מגדיל TheCounter () {counter ++; } @ ואז ("הערך של הדלפק חייב להיות אחד גדול מהערך הקודם") פומבי בטל theValueOfTheCounterMustBe1Greater () {assertTrue (1 == counter - previousValue); }}

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

4.3. הגדרת התצורה של הסיפור שלנו

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

מחלקה ציבורית IncreaseStoryLiveTest מרחיבה את JUnitStories {@Override תצורת תצורה ציבורית () {להחזיר MostUsefulConfiguration חדשה () .useStoryLoader (LoadFromClasspath חדש (this.getClass ())) .useStoryReporterBuilder (חדש StoryReporterBuilder () .withCodeLocation ). withFormats (CONSOLE)); } @ Override public InjectableStepsFactory stepsFactory () {להחזיר InstanceStepsFactory חדש (תצורה (), IncreaseSteps חדש ()); } @Override מוגן StoryPaths () {להחזיר Arrays.asList ("להגדיל. סיפור"); }}

ב storyPaths (), אנו מספקים את שלנו .כַּתָבָה נתיב הקובץ שיש לנתח על ידי JBehave. יישום הצעדים בפועל מופיע ב צעדים מפעל (). ואז פנימה תְצוּרָה(), מטעין הסיפורים ודוח הסיפור מוגדרים כהלכה.

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

4.4. סקירת תוצאות הבדיקה

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

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

אם נשכח ליישם שלב כלשהו בתרחיש, הדוח יידע אותנו על כך. תגיד שלא יישמנו את @מתי שלב:

תרחיש: כאשר משתמש מגדיל מונה, ערכו מוגדל ב- 1 בהתחשב במונה ולמונה יש ערך אינטגרלי כלשהו כאשר המשתמש מגדיל את המונה (בהמתנה) אז ערך המונה חייב להיות 1 גדול מהערך הקודם (לא בוצע )
@When ("המשתמש מגדיל את הדלפק") @ בהמתנה בטל ציבורי כאשרTheUserIncreasesTheCounter () {// PENDING}

הדו"ח היה אומר את @מתי צעד תלוי ועומד, ובגלל זה, @לאחר מכן שלב לא יבוצע.

מה אם הצעד שלנו @ ואז נכשל? אנו יכולים לזהות את השגיאה מיד מהדוח:

תרחיש: כאשר משתמש מגדיל מונה, ערכו מוגדל ב- 1 בהינתן מונה ולמונה יש כל ערך אינטגרלי כאשר המשתמש מגדיל את המונה אזי ערך המונה חייב להיות 1 גדול מהערך הקודם (FAILED) (java. lang.AssertionError)

5. בדיקת REST API

עכשיו קלטנו את היסודות של JBhave; נראה כיצד לבדוק איתו REST API. הבדיקות שלנו יתבססו על המאמר הקודם שלנו שדן כיצד לבדוק REST API עם Java.

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

5.1. בדיקת קוד הסטטוס

הסיפור:

תרחיש: כאשר משתמש בודק משתמש לא קיים ב- github, github היה מגיב 'לא נמצא' ניתן github פרופיל משתמש api ושם משתמש אקראי שלא קיים כשאני מחפש את המשתמש האקראי דרך ה- API ואז github מגיב: 404 לא נמצא כשאני מחפש eugenp1 דרך ה- API ואז github מגיב: 404 לא נמצא כשאני מחפש eugenp2 דרך ה- API ואז github מגיב: 404 לא נמצא

הצעדים:

מחלקה ציבורית GithubUserNotFoundSteps {API למחרוזת פרטית; מחרוזת פרטית nonExistentUser; פרטי int githubResponseCode; @Given ("API של פרופיל משתמש github") חלל ציבורי givenGithubUserProfileApi () {api = "//api.github.com/users/%s"; } @Given ("שם משתמש אקראי שאינו קיים") חלל ציבורי שניתן ANonexistentUsername () {nonExistentUser = randomAlphabetic (8); } @ כאשר ("אני מחפש את המשתמש האקראי דרך ה- API") הריק הציבורי כאשרILILFForTheUserViaTheApi () זורק את IOException {githubResponseCode = getGithubUserProfile (api, nonExistentUser) .getStatusLine () .getStatusCode (); } @ When ("אני מחפש משתמש $ דרך ה- API") פומבי ריק כאשרILookForSomeNonExistentUserViaTheApi (משתמש מחרוזת) זורק IOException {githubResponseCode = getGithubUserProfile (API, משתמש) .getStatusLine () .getStatusCode (); } @Then ("github תגובה: 404 לא נמצא") פומבי ריק אז GithubRespond404NotFound () {assertTrue (SC_NOT_FOUND == githubResponseCode); } // ...}

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

כמו כן, נתמכים פרמטרים עם שם מסומן:

@When ("אני מחפש שם משתמש $ דרך ה- API") בטל לציבור כאשרILookForSomeNonExistentUserViaTheApi (@Named ("שם משתמש") משתמש מחרוזת) זורק IOException

5.2. בדיקת סוג המדיה

הנה סיפור פשוט של בדיקת סוג MIME:

תרחיש: כאשר משתמש בודק פרופיל משתמש תקף ב- github, github יגיב לנתוני json נתון github פרופיל משתמש api ושם משתמש תקף כשאני מחפש את המשתמש דרך ה- API ואז github מגיב נתונים מסוג json

והנה השלבים:

מחלקה ציבורית GithubUserResponseMediaTypeSteps {API למחרוזת פרטית; פרטי מחרוזת validUser; מדיה מחרוזת פרטית פרטית; @Given ("API של פרופיל משתמש github") חלל ציבורי givenGithubUserProfileApi () {api = "//api.github.com/users/%s"; } @Given ("שם משתמש חוקי") חלל ציבורי שניתןAValidUsername () {validUser = "eugenp"; } @ כאשר ("אני מחפש את המשתמש דרך ה- API") הריק פומבי כאשרILookForTheUserViaTheApi () זורק IOException {mediaType = ContentType .getOrDefault (getGithubUserProfile (api, validUser) .getEntity ()) .getMimeType (); } @Then ("נתוני תגובה של github מסוג json") בטל בציבור ואז GithubRespondDataOfTypeJson () {assertEquals ("application / json", mediaType); }}

5.3. בדיקת המטען של JSON

ואז הסיפור האחרון:

תרחיש: כאשר משתמש בודק פרופיל משתמש חוקי ב- github, תגובת github json צריכה לכלול מטען כניסה עם אותו שם משתמש נתון פרופיל משתמש github api כשאני מחפש eugenp דרך ה- API ואז תגובת github מכילה מטען 'כניסה' זהה ל- eugenp

והטמעת צעדים פשוטים:

מחלקה ציבורית GithubUserResponsePayloadSteps {ממשק API למחרוזת פרטי; משאב GitHubUser פרטי; @Given ("API של פרופיל משתמש github") חלל ציבורי givenGithubUserProfileApi () {api = "//api.github.com/users/%s"; } @When ("אני מחפש משתמש $ דרך ה- API") בטל בציבור כאשרILookForEugenpViaTheApi (משתמש מחרוזת) זורק IOException {HttpResponse httpResponse = getGithubUserProfile (API, משתמש); resource = RetrieveUtil.retrieveResourceFromResponse (httpResponse, GitHubUser.class); } @Then ("התגובה של github מכילה מטען 'כניסה' זהה ל- $ username") פומבי ריק אזGithubsResponseContainsAloginPayloadSameAsEugenp (שם משתמש מחרוזת) {assertThat (שם משתמש, Matchers.is (resource.getLogin ()))); }}

6. סיכום

במאמר זה הצגנו בקצרה את JBehave ויישמנו בדיקות REST API בסגנון BDD.

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

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