שלווה BDD עם אביב וג'ייבה

1. הקדמה

בעבר הצגנו את מסגרת ה- Serenity BDD.

במאמר זה נציג כיצד לשלב את Serenity BDD עם Spring.

2. תלות של Maven

כדי לאפשר את השלווה בפרויקט האביב שלנו, עלינו להוסיף ליבת שלווה ו שלווה-אביב אל ה pom.xml:

 מבחן net.serenity-bdd שלווה-ליבת 1.4.0 net.serenity-bdd serenity-spring 1.4.0 

עלינו גם להגדיר את שלווה-maven-plugin, שחשוב להפקת דוחות מבחן שלווה:

 net.serenity-bdd.maven.plugins serenity-maven-plugin 1.4.0 שלווה מדווחת לאחר שילוב-מבחן מצטבר 

3. שילוב אביב

מבחן שילוב האביב צריך @לרוץ עםSpringJUnit4ClassRunner. אבל אנחנו לא יכולים להשתמש במבחן ישירות עם Serenity, מכיוון שמבחני Serenity צריכים להיות מנוהלים על ידי SerenityRunner.

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

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

3.1. SpringIntegrationMethodRule

SpringIntegrationMethodRule הוא MethodRule מוחל על שיטות הבדיקה. הקשר האביבי ייבנה לפני כן @לפני ואחרי @לפני השיעור.

נניח שיש לנו תכונה להזריק את השעועית שלנו:

 4 

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

@RunWith (SerenityRunner.class) @ContextConfiguration (locations = "classpath: adder-beans.xml") מחלקה ציבורית AdderMethodRuleIntegrationTest {@ כלל ציבור SpringIntegrationMethodRule springMethodIntegration = חדש SpringIntegrationMethodRule (); @Steps פרטי AdderSteps adderSteps; @Value ("# {props ['adder']}") מוסף פרטי פרטי; @Test הציבור בטל givenNumber_whenAdd_thenSummedUp () {adderSteps.givenNumber (); adderSteps.whenAdd (adder); adderSteps.thenSummedUp (); }}

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

@RunWith (SerenityRunner.class) @FixMethodOrder (MethodSorters.NAME_ASCENDING) @ContextConfiguration (classes = AdderService.class) מחלקה ציבורית AdderMethodDirtiesContextIntegrationTest {@Steps AdderServiceSteps הפרטי adderServiceSteps; @Rule ציבורי SpringIntegrationMethodRule springIntegration = SpringIntegrationMethodRule חדש (); @DirtiesContext @ Test public void _0_givenNumber_whenAddAndAccumulate_thenSummedUp () {adderServiceSteps.givenBaseAndAdder (randomInt (), randomInt ()); adderServiceSteps.whenAccumulate (); adderServiceSteps.summedUp (); adderServiceSteps.whenAdd (); adderServiceSteps.sumWrong (); } @Test ציבורי בטל _1_givenNumber_whenAdd_thenSumWrong () {adderServiceSteps.whenAdd (); adderServiceSteps.sumWrong (); }}

בדוגמה לעיל, כאשר אנו קוראים adderServiceSteps.whenAcumulate (), שדה מספר הבסיס של ה- @שֵׁרוּת מוזרק פנימה adderServiceSteps ישתנה:

@ContextConfiguration (class = AdderService.class) מחלקה ציבורית AdderServiceSteps {@ AdderService פרטית אוטומטית פרטית; פרטי int givenNumber; בסיס אינטימי פרטי; סכום אינטי פרטי; חלל ציבורי givenBaseAndAdder (int בסיס, int adder) {this.base = base; adderService.baseNum (בסיס); this.givenNumber = תוסף; } חלל ציבורי כאשר הוסף () {sum = adderService.add (givenNumber); } חלל ציבורי summedUp () {assertEquals (בסיס + givenNumber, סכום); } sumWrong () {בטל ציבורי) (assertNotEquals (בסיס + נתון מספר, סכום); } חלל ציבורי כאשר Accumulate () {sum = adderService.accumulate (givenNumber); }}

באופן ספציפי, אנו מקצים את הסכום למספר הבסיס:

@Service מחלקה ציבורית AdderService {int int; בסיס חלל ציבורי baseNum (int בסיס) {this.num = base; } public int currentBase () {return num; } public int להוסיף (int adder) {להחזיר this.num + adder; } ציבורי int לצבור (int adder) {להחזיר this.num + = adder; }}

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

שימו לב שגם אם סימנו עם הבדיקה הראשונה @DirtiesContext, המבחן השני עדיין מושפע: לאחר ההוספה, הסכום עדיין שגוי. למה?

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

כדי לעקוף בעיה זו, נוכל להזריק את ה- @שֵׁרוּת במקרה הבדיקה הנוכחי שלנו, ולהפוך את השירות כתלות מפורשת של צעדים:

@RunWith (SerenityRunner.class) @FixMethodOrder (MethodSorters.NAME_ASCENDING) @ContextConfiguration (classes = AdderService.class) מחלקה ציבורית AdderMethodDirtiesContextDependencyWorkaroundIntegrationTest {adderConstructorDependencySteps adderSteps adderSteps; @ AdderService פרטית אוטומטית adderService; @ לפני init בטל פומבי () {adderSteps = AdderConstructorDependencySteps חדש (adderService); } // ...}
AdderConstructorDependencySteps {class AdderService הפרטי adderService; AdderConstructorDependencySteps ציבורי (AdderService adderService) {this.adderService = adderService; } // ...}

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

@RunWith (SerenityRunner.class) @FixMethodOrder (MethodSorters.NAME_ASCENDING) @ContextConfiguration (classes = AdderService.class) מחלקה ציבורית AdderMethodDirtiesContextInitWorkaroundIntegrationTest {@Steps AdderServiceSteps הפרטי AdderServiceSteps; @ לפני init בטל פומבי () {adderServiceSteps.givenBaseAndAdder (randomInt (), randomInt ()); } // ...}

3.2. SpringIntegrationClassRule

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

@RunWith (SerenityRunner.class) @ContextConfiguration (class = AdderService.class) מחלקה מופשטת סטטית ציבורית בסיסית {@Steps AdderServiceSteps adderServiceSteps; @ClassRule ציבורי סטטי SpringIntegrationClassRule springIntegrationClassRule = SpringIntegrationClassRule חדש (); בטל כאשר Accumulate_thenSummedUp () {adderServiceSteps.whenAccumulate (); adderServiceSteps.summedUp (); } בטל כאשר Add_thenSumWrong () {adderServiceSteps.whenAdd (); adderServiceSteps.sumWrong (); } בטל כאשר Add_thenSummedUp () {adderServiceSteps.whenAdd (); adderServiceSteps.summedUp (); }}
@DirtiesContext (classMode = AFTER_CLASS) מחלקה סטטית ציבורית DirtiesContextIntegrationTest מרחיב את הבסיס {@Test public void givenNumber_whenAdd_thenSumWrong () {super.whenAdd_thenSummedUp (); adderServiceSteps.givenBaseAndAdder (randomInt (), randomInt ()); super.whenAccumulate_thenSummedUp (); super.whenAdd_thenSumWrong (); }}
@DirtiesContext (classMode = AFTER_CLASS) מעמד סטטי ציבורי AnotherDirtiesContextIntegrationTest מרחיב את הבסיס {@Test public void givenNumber_whenAdd_thenSumWrong () {super.whenAdd_thenSummedUp (); adderServiceSteps.givenBaseAndAdder (randomInt (), randomInt ()); super.whenAccumulate_thenSummedUp (); super.whenAdd_thenSumWrong (); }}

בדוגמה זו, כל ההזרקות הגלויות ייבנו מחדש לרמת הכיתה @DirtiesContext.

3.3. SpringIntegrationSerenityRunner

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

@RunWith (SpringIntegrationSerenityRunner.class) @ContextConfiguration (locations = "classpath: adder-beans.xml") מחלקה ציבורית AdderSpringSerenityRunnerIntegrationTest {@Steps פרטי AdderSteps adderSteps; @Value ("# {props ['adder']}") מוסף פרטי פרטי; @Test הציבור בטל givenNumber_whenAdd_thenSummedUp () {adderSteps.givenNumber (); adderSteps.whenAdd (adder); adderSteps.thenSummedUp (); }}

4. שילוב SpringMVC

במקרים בהם אנו זקוקים רק לבדיקת רכיבי SpringMVC עם Serenity, אנו יכולים פשוט להשתמש בהם RestAssuredMockMvc בבטוח במקום במקום שלווה-אביב שילוב.

4.1. תלות של Maven

עלינו להוסיף את התלות האביב-מדומה של mvc pom.xml:

 io. מבחן אביב-מוק-mvc 3.0.3 בטוח 

4.2. RestAssuredMockMvc בִּפְעוּלָה

בואו נבדוק כעת את הבקר הבא:

@RequestMapping (value = "/ adder", מייצר = MediaType.APPLICATION_JSON_UTF8_VALUE) @RestController מחלקה ציבורית PlainAdderController {private final int currentNumber = RandomUtils.nextInt (); @ GetMapping ("/ current") public int currentNum () {return currentNumber; } @PostMapping int intel public (@RequestParam int num) {return currentNumber + num; }}

אנו יכולים לנצל את כלי הלעג של MVC של RestAssuredMockMvc ככה:

@RunWith (SerenityRunner.class) מחלקה ציבורית AdderMockMvcIntegrationTest {@ לפני תחילת החלל הציבורית () {RestAssuredMockMvc.standaloneSetup (חדש PlainAdderController ()); } צעדים @Steps AdderRestSteps; @Test הציבור בטל givenNumber_whenAdd_thenSummedUp () זורק חריגה {steps.givenCurrentNumber (); steps.whenAddNumber (randomInt ()); steps.thenSummedUp (); }}

ואז החלק השאר אינו שונה מאופן השימוש שלנו היה סמוך ובטוח:

AdderRestSteps בכיתה ציבורית {MockMvcResponse פרטי mockMvcResponse; פרטי int currentNum; @Step ("קבל את המספר הנוכחי") חלל ציבורי givenCurrentNumber () זורק UnupportedEncodingException {currentNum = Integer.valueOf (given () .when () .get ("/ adder / current") .mvcResult () .getResponse (). getContentAsString ()); } @Step ("הוספת {0}") חלל ציבורי כאשר AddNumber (int num) {mockMvcResponse = נתון (). QueryParam ("num", num). When () .post ("/ adder"); currentNum + = מספר; } @Step ("קיבל את הסכום") בטל פומבי ואזSummedUp () {mockMvcResponse .then () .statusCode (200) .body (equalTo (currentNum + "")); }}

5. שלווה, ג'הבה, ואביב

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

תרחיש: משתמש יכול להגיש מספר למוסף ולקבל את הסכום בהתחשב במספר כשאני מגיש מספר נוסף 5 למוסף, ואז אני מקבל סכום של המספרים

אנו יכולים ליישם את ההיגיון ב- @שֵׁרוּת ולחשוף את הפעולות באמצעות ממשקי API:

@RequestMapping (value = "/ adder", מייצר = MediaType.APPLICATION_JSON_UTF8_VALUE) @RestController מחלקה ציבורית AdderController {AdderService פרטית AdderService; AdderController ציבורי (AdderService adderService) {this.adderService = adderService; } @ GetMapping ("/ current") public int currentNum () {return adderService.currentBase (); } @PostMapping int intel public (@RequestParam int num) {return adderService.add (num); }}

כעת אנו יכולים לבנות מבחן Serenity-JBehave בעזרת RestAssuredMockMvc כדלהלן:

@ContextConfiguration (מחלקות = {AdderController.class, AdderService.class}) מחלקה ציבורית AdderIntegrationTest מרחיב את SerenityStory {@ AdderService הפרטי האוטומטי AdderService; @BeforeStory בטל פומבי init () {RestAssuredMockMvc.standaloneSetup (AdderController חדש (adderService)); }}
AdderStory בכיתה ציבורית {@Steps AdderRestSteps restSteps; @Given ("מספר") חלל ציבורי givenANumber () זורק חריג {restSteps.givenCurrentNumber (); } @When ("אני מגיש מספר נוסף $ num ל- adder") בטל פומבי כאשרISubmitToAdderWithNumber (int num) {restSteps.whenAddNumber (num); } @ ואז ("אני מקבל סכום של המספרים") ריק ריק אז IGetTheSum () {restSteps.thenSummedUp (); }}

אנחנו יכולים רק לסמן SerenityStory עם @ContextConfigurationואז הזרקת אביב מופעלת באופן אוטומטי. זה עובד בדיוק כמו ה- @ContextConfiguration עַל צעדים.

6. סיכום

במאמר זה סקרנו כיצד לשלב את Serenity BDD עם Spring. השילוב לא ממש מושלם, אבל בהחלט מגיע לשם.

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


$config[zx-auto] not found$config[zx-overlay] not found