خيار 3 + جافا

قبل بضعة أشهر ، تم إصدار Cucumber JVM 3.0.0. تم تصميم الإصدار الجديد لجعل العمل مع إطار BDD هذا أكثر وضوحًا ومرونة. في هذه المقالة سأتحدث عن التغييرات والميزات الجديدة ، فضلا عن إعطاء أمثلة على استخدامها.

تنفيذ تعابير الخيار


في الإصدار الثالث من Cucumber JVM ، تتوفر Cucumber Expressions الآن ، وهي لغة تعبير بسيطة للعثور على سلاسل فرعية في النص. على عكس التعبيرات العادية ، تم تحسين هذه اللغة من أجل سهولة القراءة ، مما يجعلها أكثر منطقية في سياق الخيار. إذا كنت بحاجة إلى المرونة ، فلا يزال بإمكانك استخدام التعبيرات العادية.

على سبيل المثال ، لدينا الميزة التالية:

# language: ru :     : *       15 *     "" *     hello 

للحصول على الحجج منه ، يمكنك استخدام الوصف التالي للخطوات:

  @("      {int}") public void giveInt(Integer int1) { System.out.println(int1); } @("    {string}") public void giveString(String string) { System.out.println(string); } @("    {word}") public void giveWord(String string) { System.out.println(string); } 

كما ترى من المثال ، تتكون تعبيرات الخيار من قوسين مجعدين بنوع القيمة المرسلة.

تتوفر أنواع العتاد التالية خارج الصندوق:

  • {int}
  • {تعويم}
  • {سلسلة}
  • {كلمة}
  • {biginteger}
  • {bigdecimal}
  • {بايت}
  • {short}
  • {طويل}
  • {مزدوج}

تتطابق {string} مع سلسلة مقتبسة ، و {word} مع كلمة واحدة بدون علامات اقتباس (في وقت كتابة هذا التقرير ، لا يمكن إرسال سوى الكلمات المكتوبة بالحروف اللاتينية إلى التعبير {word}).

يمكنك إنشاء نوع البيانات الخاص بك ، على سبيل المثال ، نريد نقل كائن فئة LocalDate من ميزة:

 # language: ru :    : *     01.06.2018 

  @("    {localdate}") public void ___(LocalDate localdate) { System.out.println(localdate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))); } 

للقيام بذلك ، في الحزمة المحددة في الغراء ، تحتاج إلى إنشاء فئة تطبق واجهة TypeRegistryConfigurer ، ومن خلالها أضف نوع البيانات إلى التسجيل:

 public class TypeRegistryConfiguration implements TypeRegistryConfigurer { @Override public Locale locale() { //        float  double return new Locale("ru"); } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { //       typeRegistry.defineParameterType(new ParameterType<>( //  ,    : "localdate", // ,      : "[0-9]{2}.[0-9]{2}.[0-9]{4}", //  : LocalDate.class, // ,       (Transformer<LocalDate>) s -> { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); return LocalDate.parse(s, formatter); } )); } } 

يجب أن تكون الفئة التي تطبق واجهة TypeRegistryConfigurer واحدة في المشروع ، وإلا سيتم طرح استثناء.

تسمح لك تعبيرات الخيار أيضًا بتحديد نص اختياري بين قوسين:

  @("Hello, world(s)!") public void getHello() { System.out.println("Hello world!"); } 

لا يمكنك استخدام المسافات داخل الأقواس (في وقت الكتابة ، يتم دعم الأبجدية اللاتينية فقط).

يتم تحديد النص البديل من خلال الشرطة المائلة:

  @("/ ") public void getAlternative() { System.out.println("Hello world!"); } 

 # language: ru :     : *   *   

يمكنك الهروب من {} و () بخط مائل.

لا يمكنك استخدام التعبيرات العادية وتعبيرات الخيار في تعريف الخطوة نفسه.

هجر XStream


في الإصدارين الأول والثاني من الخيار ، تم استخدام التعبيرات العادية ومكتبة XStreamsConverters لتحديد نوع البيانات المرسلة. في الإصدار الثالث من Cucumber ، تخلى المطورون عن استخدام مكتبة XStreamsConverters.

كان الأساس المنطقي للتخلي عن XStreamConverters هو التوثيق الضعيف ، وعدم القدرة على استخدام مخططي الكائنات من جهة خارجية ، وعدم وجود دعم لـ Java 9.
لم يعد محدد التعليقات التوضيحية والتنسيقات والمحولات وغيرها من التعليقات التوضيحية من XStream يعمل. بدلاً من ذلك ، تحتاج الآن إلى استخدام ParameterType أو DataTableType.

DataTable


لقد خضع نوع بيانات DataTable أيضًا لتغييرات.

كما هو الحال في الإصدارات السابقة ، يتعامل Cucumber 3 مع تحويل DataTable بعمود واحد إلى قائمة ، وعمودين إلى الخريطة ، وما إلى ذلك دون أي مشاكل. ولكن هذا يعمل فقط إذا قمت بتحويل البيانات إلى أحد الأنواع التالية: String أو Integer أو Float أو Double أو Byte أو Short أو Long أو BigInteger أو BigDecimal.

إذا كنت ترغب في إنشاء كائن من فئة أخرى من DataTable ، فأنت ، كما هو الحال بالنسبة لنوع بيانات مخصص ، تحتاج إلى كتابة المحول الخاص بك:

 # language: ru :     DataTable :      |  |  | 09.02.1887 | |  |  | 23.02.1890 | 

User.java
 import java.time.LocalDate; public class User { private String firstName; private String lastName; private LocalDate birthDay; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public LocalDate getBirthDay() { return birthDay; } public void setBirthDay(LocalDate birthDay) { this.birthDay = birthDay; } @Override public String toString() { return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", birthDay=" + birthDay + '}'; } } 


  @("   ") public void ___(List<User> users) { System.out.println(users); } 

تتم إضافة المحول إلى التسجيل بنفس الطريقة كما في المثال مع نوع بيانات المستخدم:

 public class TypeRegistryConfiguration implements TypeRegistryConfigurer { @Override public Locale locale() { return new Locale("ru"); } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { //       DataTableType typeRegistry.defineDataTableType(new DataTableType( User.class, (TableRowTransformer<User>) list -> { User user = new User(); user.setFirstName(list.get(0)); user.setLastName(list.get(1)); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); user.setBirthDay(LocalDate.parse(list.get(2), formatter)); return user; } )); } } 

قبل وبعد السنانير الخطوة


ابتكار آخر هو الخطوة السابقة واللاحقة. يمكنك الآن تحديد الخطافات التي سيتم استدعاؤها قبل و / أو بعد كل خطوة من البرنامج النصي.

تتبع الخطافات المتشابهة القواعد نفسها التي تتبعها الخطافات على مستوى البرنامج النصي:

  • يمكن تعليق العلامات على الخطافات لتشغيلها فقط في سيناريوهات معينة ؛
  • يمكنك تعيين ترتيب تنفيذ السنانير.
  • سيتم تنفيذ AfterStep حتى إذا كانت الخطوة التي كان من المفترض أن يتم تنفيذها بعد فواصلها.

 # language: ru :  @hooks :      ,                 @only_scenario_hooks :                 @only_step_hooks :                  

 //  not     //       hooks  only_scenario_hooks @Before(value = "(@hooks or @only_scenario_hooks) and not @only_step_hooks") public void before() { System.out.println("before scenario"); } //         only_step_hooks @BeforeStep(value = "@only_step_hooks") public void beforeStep() { System.out.println("before step"); } //         only_step_hooks @AfterStep(value = "not(@hooks or @only_scenario_hooks) and @only_step_hooks") public void afterStep() { System.out.println("after step"); } //       hooks  only_scenario_hooks @After(value = "@hooks or @only_scenario_hooks") public void after() { System.out.println("after scenario"); } 

في الختام ، أود أن أقول أنه حتى إذا استخدمت قدرات XStream في مشاريعك ومع الانتقال إلى الإصدار الجديد من Cucumber ، سيكون من الضروري إجراء تحسينات صغيرة ، أوصي بذلك. يتم دعم الخيار وتطويره بنشاط ، وتجعل الميزات الجديدة استخدامه أكثر مرونة ومفهومة.

تحديث 09/23/2018
اليوم ، تم إصدار الخيار 4.0.0. لن أصف جميع التغييرات ، سأقول فقط أنه الآن يتم دعم اللغة الروسية بشكل طبيعي في تعبيرات Cucumber Express ، كما أن المثال الذي كتبته باستخدام {string} و {word} لن يعمل بعد الآن. والحقيقة هي أن {word} يمكن أن تحتوي الآن على أي حرف غير مسافة بيضاء ، مما يتسبب في حدوث تعارض عند البحث عن خطوة التنفيذ:

 # language: ru :     : *     "" *     hello 


  @("    {string}") public void giveString(String string) { System.out.println(string); } @("    {word}") public void giveWord(String string) { System.out.println(string); } 


المراجع:

أمثلة من المقال
مقالتي عن النسخة الأولى من Cucumber JVM

Source: https://habr.com/ru/post/ar422651/


All Articles