בדיקת 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, עלינו לבצע את השלבים הבאים:
- כתוב סיפור משתמש
- מיפוי שלבים מסיפור המשתמש לקוד ג'אווה
- הגדר סיפורי משתמשים
- הפעל בדיקות JBehave
- סקור תוצאות
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.