PieceofScript هي لغة بسيطة لكتابة البرامج النصية للاختبار التلقائي لواجهة برمجة تطبيقات HTTP JSON.
يتيح لك PieceofScript:
- وصف طرق API بتنسيق YAML ، مع اسم الطريقة بلغة طبيعية تقريبًا ، وهي مناسبة لقراءة الاختبارات
- مرنة بما يكفي لوصف النماذج بتنسيق YAML وتوليد بيانات عشوائية منها
- كتابة نصوص مكالمات API معقدة بلغة سهلة القراءة مع بناء بسيط
- الحصول على نتائج الاختبار بتنسيقات JUnit و HTML
كتبت هذه "الدراجة" لأن واجهة SoapUI دفعتني إلى الأسفل. كنت أرغب في وصف الاختبارات بكل بساطة ووضوح في محرر نصوص بدون واجهة مستخدم رسومية خاصة. بالإضافة إلى ذلك ، لا يستوعب git ملف xml الضخم الذي يصدر SoapUI ، لذا من الصعب وضع اختبارات لمهمة معينة في نفس الفرع حيث تم تنفيذ المهمة نفسها. تعد واجهة Postman أجمل بكثير ، ولكن عند التطوير ، يستغرق الأمر وقتًا طويلاً لإنشاء / تعديل الطلبات هناك وتكرارها بالتسلسل الصحيح. كنت أرغب في أتمتة ذلك. لقد درست أيضًا أدوات اختبار أخرى ، وكان لكل منها "
خلل قاتل " ، لذلك في حالة
متلازمة NIH فتحت IDE.
إليكم ما جاء منها.

المترجم مكتوب بلغة PHP وهو أرشيف فارسي ، ويتطلب إصدار PHP 7.2 ، على الرغم من أنه قد يعمل أيضًا على 7.1. كود المصدر والوثائق
https://github.com/maximw/PieceofScript . التوثيق قيد التطوير. هذا ، كما اتضح ، هو الجزء الأصعب والممل.
مشروع اختبار وهيكله وإطلاقهاختبار البرنامج النصيطرق اختبار APIاستدعاء أسلوب APIتوليد النماذج وبيانات الاختباروظائف مدمجةحالات الاختبارالمتغيرات والمجالاتأنواع وعملياتحفظ البيانات بين الجريالإخراج إلى stdout والتقاريرأمثلة - كلمات كافية ، أظهر الرمز!
التعليقات والخطط للمستقبل إن وجدتمشروع اختبار وهيكله وإطلاقه
المشروع عبارة عن دليل يحتوي على مجموعة من ملفات البرامج النصية وملفات وصف طريقة API ومولدات بيانات الاختبار.
في الإصدار الأدنى ، يبدو المشروع كما يلي:
./tests endpoints.yaml - API generators.yaml - start.pos -
ملف بدء التشغيل هو البرنامج النصي الذي تبدأ منه عملية الاختبار. يتم تعيينه عند بدء التشغيل:
pos.phar run ./start.pos --junit=junit_report.xml -vvv --config=config.yaml
تتم قراءة جميع المسارات النسبية من دليل العمل الذي يحتوي على ملف البدء.
يمكن تحديد ملف التكوين في سطر الأوامر مع الخيار -
التكوين أو وضع
config.yaml في دليل العمل. التكوين اختياري ، تحتاج إلى التسلق هناك حسب الحاجة.
المزيد عن التكوين .
اختبار البرنامج النصي
لنفسي ، قررت كتابة نصوص برمجية في ملفات بامتداد .pos ، حتى تتمكن من عمل إعدادات تمييز الكود في IDE بامتداد ملحق. لكن المترجم غير مكترث بالامتداد.
في ما يلي مثال بسيط للنص البرمجي لمنتدى خيالي حيث يتم إجراء اختبار إنشاء وقراءة منشور من قبل مستخدمين مختلفين.
require "./globals.pos"
نعم ، إنها لا تبدو جيدة جدًا بدون إضاءة خلفية.
يبدأ كل سطر من النص البرمجي بعامل ، أو هو استدعاء لأسلوب API. إذا بدأ اسم طريقة واجهة برمجة التطبيقات فجأة بكلمة تتطابق مع أحد عوامل التشغيل ، يمكنك استخدام الرمز "
> ":
>Include $user to group $userGroup
عوامل التشغيل غير حساسة لحالة الأحرف. تأكيد ، ASSERT أو aSsErT (ولكن لماذا تكتب مثل هذا؟) ستعمل.
يجب أن يكون كل بيان أو استدعاء أسلوب API على سطر منفصل. لكن التفاف السطر ممكن أيضًا إذا كان الحرف الأخير من السلسلة هو
\ (مرحبًا ، Python).
تفاصيل غير مثيرة للاهتمام حول فواصل الأسطر والمسافات البادئةإذا تم استخدام التفاف السطر في تعليق ، فسيتم اعتبار السطر التالي أيضًا جزءًا من التعليق. عند لف الخطوط داخل الكتل (
testcase ،
if ،
while ،
foreach ) ، من المهم وضع
مسافة بادئة بحيث يقع السطر التالي في نفس الكتلة.
var $n = 20 var $i = 2 var $fib1 = 1; \ $fib2 = 1 while $i <= $n var $fib_sum = \ $fib2 + $fib1 print toString($i) + " :" + \ toString($fib_sum) var $fib1 = $fib2 var $fib2 = $fib_sum var $i = $i + 1
عند تنفيذ عبارات الكتلة (
testcase ،
if ،
while ،
foreach ) ، يتم تحديد الكتلة من خلال المسافة البادئة لخطوطها. تُحسب المسافة البادئة كعدد المسافات البيضاء في بداية السطر. يتم احتساب كل من المسافة وعلامة التبويب كحرف واحد ، ولكن يتم عادةً عرض علامات التبويب في المحررين كمسافات متعددة. لذلك ، لتجنب الارتباك ، من الأفضل استخدام علامات التبويب أو المسافات ، ولكن ليس جميعًا معًا.
القائمة الكاملة للمشغلين
يتطلب fileName - قم بإرفاق الملف في المكان الذي يتم فيه استدعاء عامل التشغيل. سيبدأ الملف المرفق على الفور من السطر الأول. عند الانتهاء ، يعود المترجم إلى السطر التالي من الملف المصدر. إذا كان الملف المطلوب غير قابل للقراءة ، فسيتم إنشاء خطأ. يتم حساب المسار النسبي من دليل العمل.
تضمين fileMask - على النحو المطلوب ، ولكن إذا كان الملف المطلوب غير قابل للقراءة ، فلن يكون هناك خطأ. هذا مناسب ، على سبيل المثال ، لإنشاء إعدادات لبيئات الاختبار المختلفة. بالإضافة إلى ذلك ، يمكن تضمين جميع الملفات عن طريق القناع مرة واحدة. لذا ، على سبيل المثال ، يمكنك تنزيل أدلة كاملة للملفات التي تحتوي على حالات اختبار. ولكن في نفس الوقت ، لا يتم ضمان أي ترتيب لتنزيل الملفات.
var $ variable1 = تعبير 1 ؛ متغير $ 2 = تعبير 2 ؛ ... ؛ $ variableN = expressN - تعيين القيم للمتغيرات. إذا كان المتغير غير موجود بالفعل ، فسيتم إنشاؤه في السياق الحالي.
السماح $ متغير 1 = التعبير 1 ؛ متغير $ 2 = تعبير 2 ؛ ... ؛ $ variableN = expressN - تعيين القيم للمتغيرات. إذا لم يكن المتغير في السياق الحالي ، فستكون هناك محاولة لإنشاء أو تعديل المتغير في السياق العام.
const $ const1 = التعبير 1 ؛ const2 $ = تعبير 2 ؛ ... ؛ $ constN = expressN - حدد قيمة الثوابت في السياق الحالي. الفرق بين الثوابت والمتغيرات هو أنه لا يمكن تغييرها ؛ عندما تحاول تعيين قيمة إلى ثابت ، سيتم إصدار تحذير بعد الإعلان. إذا كان هناك بالفعل متغير يحمل نفس الاسم ، فسيتم إنشاء خطأ عند محاولة تعريفه ثابتًا. خلاف ذلك ، كل ما هو صحيح للمتغيرات صحيح أيضا للثوابت.
استيراد $ متغير 1 ؛ متغير $ 2 ؛ ... ؛ $ variableN - ينسخ المتغيرات من السياق العام إلى السياق الحالي. قد يكون من المفيد إذا كنت بحاجة إلى العمل على قيمة متغير عام ، ولكن ليس تغييره.
testcase testCaseName - يعلن عن حالة اختبار ، والتي يمكن بعد ذلك أن يطلق عليها كوحدة مع بيان
التشغيل .
اقرأ المزيد عن حالات الاختبار لاحقًا في المقالة .
تأكيد التعبير - تحقق من
صحة التعبير ، أو اطبع تقريرًا عن الاختبار الفاشل.
يجب أن يكون التعبير هو نفس
التأكيد ، فقط إذا فشل الاختبار ، سيتم إيقاف حالة الاختبار الحالية. وخارج سياق حالة الاختبار ، سيتم إنهاء البرنامج النصي تمامًا. يمكن استخدامه إذا تم اكتشاف خطأ لا معنى له من عمليات الفحص الإضافية.
تشغيل testCaseName - تشغيل حالة الاختبار المحددة للتنفيذ.
تشغيل دون تحديد اسم حالة الاختبار سيبدأ جميع حالات الاختبار المعلنة التي لا تتطلب الحجج بترتيب إعلانها.
بينما التعبير - حلقة ، بينما
يكون التعبير صحيحًا ، ينفذ العبارات بخطوط ذات مسافة بادئة أكثر من
حين .
foreach $ صفيف ؛ عنصر $ - حلقة عبر الصفيف ، يتم تنفيذ نص الحلقة لكل عنصر تالي من الصفيف. من الممكن أيضًا الحصول على المفتاح
لكل صفيف $ ؛ مفتاح $ عنصر $ . يتم إنشاء / الكتابة فوق متغيرات
مفتاح $ و
$ element في السياق الحالي.
إذا كان التعبير - إذا كان
التعبير صحيحًا ، فسيتم تنفيذ العبارات بخطوط ذات مسافة بادئة أكثر من
لوالتعبير المطبوع 1 ؛ تعبير 2 ؛ ... تعبير N - اطبع قيمة
التعبير M إلى stdout. يمكن استخدامه لتصحيح الأخطاء ، وهو يعمل فقط مع مستوى "
التفاؤل " -
الإفراط = 1 أو
-v وأكثر.
تعبير السكون - توقف مؤقتًا لرقم معين ، اختياريًا عددًا صحيحًا ، ثانية. في بعض الأحيان تحتاج إلى إعطاء API اختبارها استراحة.
تعبير الإيقاف المؤقت - ليس في الوضع التفاعلي (خيار سطر الأوامر
-n ) يشبه
السكون . يعد
التعبير اختياريًا ، وفي هذه الحالة لن يكون هناك توقف مؤقت. وفي الوضع التفاعلي ، توقف مؤقتًا قبل الضغط على Enter.
اختبار
إلغاء نهاية. المترجم ينهي العمل وينشئ التقارير.
طرق اختبار API
هذا في الواقع ما تحتاج إلى اختباره - اتصل بمعلمات معينة وتحقق مما إذا كانت الإجابة تلبي التوقعات.
يتم وصف طرق API بتنسيق YAML. بشكل افتراضي ، يجب أن تكون الأوصاف في ملف
endpoints.yaml للدليل الحالي و / أو في ملفات
* .yaml في
دليلها الفرعي
.endpoints . قبل الاختبار ، سيحاول المترجم قراءة جميع هذه الملفات دفعة واحدة.
مثال على
endpoints.yaml بنية:
Auth $user: method: "POST" url: $domain + "/login" headers: Content-Type: "application/json" format: "json" data: login: $user.login password: $user.password after: - assert $response.code == 200 - let $user.auth_token = $response.body.auth_token Create post $post by $user: method: "POST" url: $domain + "/posts" format: "json" data: $post headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 201 Read post $postId by $user: method: "GET" url: $domain + "/posts/" + $postId headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert ($response.code == 200) || ($response.code == 404) Create comment $comment on $post by $user: method: "POST" url: $domain + "/comments/create/" + $post.id format: "json" data: $comment headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 201
اسم طريقة API (المستوى الأعلى من بنية YAML) التي يمكن من خلالها تسميتها عبارة عن سلسلة بتنسيق شبه عشوائي.
يمكن تحديد الحجج في أي مكان في الاسم. يجب أن تكون مفصولة بمسافات عن بقية الكلمات. على سبيل المثال ،
$ comment و
$ post و
$ user في الطريقة الأخيرة.
أيضًا ، في أي مكان في الاسم ، يمكنك تحديد قيم الطريقة الاختيارية في أقواس متعرجة مزدوجة.
Get comments of $post {{$page=1; $perPage=$defaultGlobalPageSize}}: method: "GET" url: $domain + "/comments/" + $post.id query: page: $page per_page: $perPage headers: auth: "Bearer " + $user.auth_token content-type: "application/json" after: - assert $response.code == 200
في التعبيرات التي تحدد القيم الاختيارية ، تتوفر متغيرات السياق العامة.
يمكن أن تكون القيم الاختيارية مفيدة بحيث لا تحددها في كل مرة تتصل فيها بطريقة API. إذا كان حجم الصفحة يحتاج إلى تغيير في مكان واحد فقط ، فلماذا أشير إليه في جميع الأماكن الأخرى؟ أمثلة على المكالمات لهذه الطريقة:
Get comments of $newPost // $page $perPage Get comments of $newPost {{$page=$currentPage+1}} Get comments of {$newPost} {{$perPage=10;$page=100}}
سيتم أخذ بقية المتغيرات المستخدمة (
المجال $ في المثال أعلاه) من السياق العام. سأخبرك المزيد
عن السياقات لاحقًا.
يبدو لي أنه من المناسب إعطاء طرق API لأسماء يمكن قراءتها بلغة طبيعية ، ثم يكون من السهل قراءة البرنامج النصي للاختبار. الأسماء غير حساسة لحالة الأحرف ، على سبيل المثال ، يمكن استدعاء أسلوب
Auth $ User كمستخدم
auth $ ومستخدم AUTH $ . ومع ذلك ، فإن أسماء المتغيرات حساسة لحالة الأحرف ، والمزيد
حول المتغيرات أدناه.
ملاحظة مهمة. يتيح لك تنسيق YAML عدم وضع سلاسل بين علامتي اقتباس. ولكن بالنسبة للمترجم ، فإن السلسلة بدون علامات الاقتباس هي تعبير يحتاج إلى تقييم. على سبيل المثال ، سيؤدي الإعلان عن
url: http://example.com/login
field إلى حدوث خطأ في بناء الجملة أثناء التنفيذ. لذلك ، سيكون صحيحا:
url: "http://example.com/login"
أو
url: "http://"+$domain+"/login"
حقول وصف طريقة API
الطريقة - طريقة HTTP المطلوبة
url - عنوان URL الفعلي المطلوب
رؤوس - قائمة رؤوس HTTP ، اختيارية
ملفات تعريف الارتباط - قائمة ملفات تعريف الارتباط الاختيارية
المصادقة - بيانات لمصادقة HTTP ، اختيارية
auth: login: $login password: $password type: "basic"
الاستعلام - قائمة معلمات URL ، اختياري
الشكل - إحدى القيم:
- بلا - الطلب ليس له جسم
- json - إرسال إلى JSON
- raw - إرسال السلسلة "كما هي"
- شكل - في تنسيق التطبيق / x-www-form-urlencoded
- متعدد الأجزاء - بتنسيق بيانات متعدد الأجزاء / النماذج
اختياري ، افتراضي
سيتم إرسال نص طلب
البيانات بالتنسيق المحدد في
التنسيق ، اختياري
يجب أن تكون الملفات المحددة في حقول
الملفات قابلة للقراءة. إذا تم تحديد عنوان URL ، فيجب تمكين
allow_url_fopen في php.ini
قبل - البيانات التي سيتم تنفيذها قبل طلب HTTP ، اختياري
بعد - العبارات التي سيتم تنفيذها بعد طلب HTTP ، اختياري
إن فكرة الكتل
قبل وبعد إجراء عمليات التحقق أو معالجة أي بيانات مطلوبة في كل مرة قبل أو بعد تنفيذ طلب HTTP تملي ليس عن طريق اختبار الاحتياجات كما هو الحال مع منطق الأعمال. على سبيل المثال ، نسخ رمز التفويض الذي تم إصداره إلى حقل بنية المستخدم $ لاستدعاء جميع أساليب واجهة برمجة التطبيقات اللاحقة نيابة عن هذا المستخدم. أو للتحقق من حالة HTTP للاستجابة ، حتى لا يتم التحقق منها في كل مرة بعد إجراء مكالمة في البرنامج النصي.
استدعاء أسلوب API
لاستدعاء طريقة API في البرنامج النصي ، تحتاج إلى تحديد اسمها ومعلماتها ، إذا لزم الأمر. فيما يلي مثال لاستدعاء طريقة API الأخيرة من الوصف أعلاه:
Create comment $comments.1 on {$newPost} by {$postAuthor}
إذا كانت المعلمة محاطة بأقواس متعرجة ، فسيتم تمريرها حسب القيمة - وبهذه الطريقة يمكنك تمرير أي تعبير. إذا حددت معلمة بدون أقواس متعرجة ، فسيتم تمريرها حسب المرجع - يمكن أن تكون فقط متغيرات ووصول ثابت إلى عناصر الصفيف (خلال فترة ، ولكن ليس عبر أقواس []).
Create comment {$comments[$i]} on $posts.0 by $users.1 Read post {123} by $user Get comments of $users.1.id {{$page = 2}}
في كل مرة يتم استدعاء طريقة API في سياق المكالمة نفسها (في قوائم العبارات
قبل وبعد ) وفي السياق الذي تم استدعاؤه ، يتم إنشاء المتغيرات
$ request و
$ response . هذه أسماء محجوزة ، لا أوصي باستخدامها لأغراض أخرى. يتوفر
طلب $ في كلٍ من الكتل
قبل وبعد الكتل ، وتكون
استجابة $ فقط
بعد ذلك ،
قبل أن تصبح قيمته
خالية . في سياق الاستدعاء ، تكون هذه المتغيرات متاحة حتى استدعاء طريقة API التالية ، حيث سيتم إعادة تهيئتها.
- هيكل الطلب
$ request.method - سلسلة - طريقة HTTP
$ request.url - سلسلة - عنوان URL المطلوب
request.query $ - صفيف - قائمة معلمات GET
$ request.headers - صفيف - قائمة رؤوس الطلبات
$ request.cookies - صفيف - قائمة ملفات تعريف الارتباط
بيانات reuqest.auth $ - صفيف أو خالية - لمصادقة HTTP
$ request.format - سلسلة - تنسيق بيانات الطلب
بيانات $ request.data - اكتب أي - ما تم حسابه في حقل
البيانات- هيكل الاستجابة
$ response.network - منطقي - خطأ إذا كان الخطأ على مستوى الشبكة أقل من HTTP
$ response.code - الرقم أو Null - رمز الاستجابة ، على سبيل المثال ، 200 أو 404
$ response.status - String or Null - response status ، على سبيل المثال ، "204 No Content" أو "401 Unauthorized"
$ response.headers - صفيف - قائمة رؤوس الاستجابة وأسماء الرؤوس صغيرة
$ response.cookies - Array - قائمة ملفات تعريف الارتباط
$ response.body - أي نوع - نص استجابة يتم معالجته كـ JSON ، إذا كان هناك خطأ أثناء التحليل ، فلن يكون هناك أي عنصر في
الجسم على الإطلاق:
@response.body == null
(
حول التحقق من وجود المتغيرات )
$ response.raw - String or Null - نص الاستجابة الأولية
$ response.duration - اكتب الرقم - مدة الطلب بالثواني
توليد النماذج وبيانات الاختبار
تستخدم المولدات لوصف النماذج وتوليد بيانات الاختبار منها. يجب أن تكون الأوصاف بتنسيق YAML في ملف
generators.yaml في دليل العمل و / أو ملفات
* .yaml في الدليل الفرعي
.gengenators .
User: body: login: Faker\login() name: Faker\name() email: Faker\email() password: Faker\text(16) child: Child() birthday: dateFormat(Faker\datetime(), "U") settings: notifications_enabled: Faker\boolean() Child: body: name: Faker\name() gender: Faker\integer(1, 2) age: Faker\integer(0, 18) Comment($user): body: content: "Hi! I'm " + $user.name tags: - "tag1" - "tag2"
في المثال أعلاه ، يتم الإعلان عن المولدات الثلاثة
User () و
Child () و
Comment () . في هذه الحالة ، هذا الأخير لديه الوسيطة
$ user ويمكنه استخدام هذه البيانات عند الإنشاء. يتم دائمًا تمرير الحجج إلى المولدات بالقيمة. بالإضافة إلى ذلك ، يستخدم المثال العديد من الوظائف المضمنة:
Faker \ name () ،
Faker \ email () ،
dateFormat () ، إلخ.
قسم عن الوظائف المضمنة .
عند استدعاء مُنشئ
User () من المثال أعلاه ، سيتم إنشاء هيكل يشبه هذا في JSON:
{ "login": "fgadrkq", "name": "Lucy Cechtelar", "email": "tkshlerin@collins.com", "password": "gbnaueyaaf", "child": { "name": "Adaline Reichel", "gender": 2, "age": 12 }, "birthday": 318038400, "settings": { "notifications_enabled": true } }
قيمة المجال التابع هي نتيجة منشئ
Child () .
كما هو الحال في وصف أساليب API ، يتم التعامل مع أي سلاسل غير مضمنة بين علامتي اقتباس كتعبيرات يتم تقييمها. يمكن أن يكون هذا ليس فقط استدعاء لمولد آخر ، ولكن تعبيرًا تعسفيًا ، على سبيل المثال ، في منشئ
التعليق (مستخدم $) ، يمثل حقل
المحتوى سلسلة من السلسلة Hi! أنا والاسم الذي تم تمريره إلى
$ userأسماء المولدات غير حساسة لحالة الأحرف ويجب أن تبدأ بحرف لاتيني ؛ يمكن أن تحتوي على أحرف لاتينية وأرقام وشرطات سفلية وشرطات مائلة.
نظرًا لأن بنية استدعاء المولدات والوظائف المضمنة هي نفسها ، فإنها تشترك في مساحة اسم مشتركة. من خلال الاصطلاح ، أقترح استخدام شرطة مائلة للخلف كفاصل لتحديد "بائع" أو مكتبة من الوظائف المضمنة ، مثل وظائف Faker \ something () ، استنادًا إلى مكتبة
github.com/fzaninotto/Faker .
الفروق الدقيقة في استخدام المولدات ، لا يمكنك القراءةباستخدام المولدات ، يمكنك إنشاء هياكل البيانات:
# Userredentials $user Userredentials($user): body: login: $user.email password: $user.password # . , GlobalSearchResult($posts, $comments, $users): body: posts: title: " " list: $posts comments: title: " " list: $comments users: title: " " list: $users
GlobalSearchResult ليست بيانات اختبار يتم إرسالها في الطلب إلى طريقة واجهة برمجة التطبيقات ، ولكنها نموذج استجابة يمكن التحقق منه بما سترسله واجهة برمجة التطبيقات ، على سبيل المثال ، باستخدام الدالات
المماثلة () أو
المتطابقة () .
يمكن للمولد تغيير الهيكل الذي تم الحصول عليه في
الجسم باستخدام الهياكل المحسوبة في حقول
الاستبدال والإزالة. سأريكم مثالا.
افترض أن لديك بالفعل منشئ
User () الذي ينشئ بنية البيانات الصحيحة للمستخدم. تحتاج الآن إلى التحقق من كيفية استجابة API إذا قمت بتقديم بيانات غير صحيحة. يمكنك الذهاب بطريقتين:
- إنشاء مولد مستخدم "خاطئ" من البداية. ولكن بعد ذلك ، سنحصل على تكرار الشفرة ، وبعد ذلك ، على سبيل المثال ، عند إضافة حقل جديد إلى المستخدم وفقًا لاحتياجات منطق الأعمال ، سيتعين عليك إجراء تغييرات في مكانين. جاف!
- يمكنك "ترثه" من بنية User () الموجودة عن طريق تعيينه في النص الأساسي. وفي الاستبدال والإزالة ، قم بتعيين الحقول التي سيتم إضافتها / تغييرها وحذفها.
# , , # InvalidUser($user): body: $user replace: email: Faker\String(6, 15) # password: Faker\String(1, 5) # new_field: " , " remove: name: size($user.name) < 10 # , 10 # , # InvalidNewUser: body: User() replace: login: "!@#$%^&*" # remove: about: true settings: notifications: 100500 # , # true
عندما يعمل المولد ،
يتم حساب بنية البيانات في
الجسم أولاً ، ثم يتم استبدالها واستكمالها بعناصر من
الاستبدال ، ثم يتم حذف الحقول المحددة في
الإزالة إذا كانت قيمتها مساوية لـ
true . إذا لم تكن نتيجة حساب
الجسم أو
الاستبدال أو
الإزالة عبارة عن مصفوفة ، فلن يكون هناك خطأ ، ولكن لا توجد نقطة في هذا أيضًا ، لأنه لن تكون هناك حقول يمكن استبدالها وحذفها.
وظائف مدمجة
قائمة كاملة بالوظائف المضمنة . على سبيل المثال ، سأعطي بعضها فقط.
بعد اسم الدالة وقائمة الوسيطات ، يشار إلى
نوع القيمة المرتجعة ، إذا تم تحديدها.
العمليات مع المتغيرات:
متشابه ($ var، $ sample، $ checkTypes)
منطقي - إرجاع
صحيح إذا كانت الوسيطات من نفس النوع ، إذا كان
$ var مصفوفة ، فيجب أن تكون جميع مفاتيح السلسلة الموجودة في
$ sample في
$ var ، إذا كان
$ checkTypes صحيحة ، ثم يجب أن تتطابق أنواع العناصر المقابلة. وبعبارة أخرى ، فإن عناصر المصفوفة
var var هي مجموعة فرعية من عناصر
العينة $ .
متطابقة ($ var، $ sample، $ checkTypes) Boolean هو تناظري مماثل () ، مع العكس الإضافي ، في حالة المصفوفات ، يجب أن تكون جميع مفاتيح السلسلة في $ var في $ sample أيضًا . وبعبارة أخرى ، فإن عناصر المصفوفة var var تساوي عناصر المصفوفة $ sample حتى نوع العنصر.max ($ var1، $ var2، ... $ varN) - الحد الأقصى للقيم التي تم تمريرها (إذا كان من الممكن مقارنتها).min ($ var1، $ var2، ... $ varN) - الحد الأدنى للقيم التي تم تمريرها.إذا ($ condition، $ var1، $ var2) - إذا كان $ condition == true ، فسوف يُرجع $ var1 ، وإلا $ var2. استبدال عامل التدريب (مرحبا MySQL).الاختيار ($ condition1، $ var1، $ condition2، $ var2، ...، $ conditionN، $ varN) - سيعرض أول $ varK الذي تمت مواجهته إذا كان $ conditionK == true.العمل مع الأوتار:
size ($ string) Number - طول السلسلة بترميز UTF-8.regex ($ string، $ regex) منطقي - تحقق من السلسلة للتعبير العادي .regexMatch ($ string، $ regex) Array - سيتم إرجاع مجموعة من السلاسل - تتطابق مع المجموعات العادية regex $ .معالجة الصفيف:
صفيف ($ var1 ، $ var2 ، ... $ varN) صفيف - ينشئ مصفوفة من العناصر التي تم تمريرها.size ($ array) Number - عدد العناصر في المصفوفة.keys ($ array) Array - قائمة المفاتيح في المصفوفة.slice ($ array، $ offset، $ length) Array - جزء من المصفوفة من $ offset من $ length ، ( المزيد ).append ($ array، $ value) Array - إضافة عنصر إلى نهاية المصفوفة.prepend ($ array، $ value) Array - إضافة عنصر إلى بداية المصفوفة.معالجة التاريخ:
dateFormat ($ date، $ format) السلسلة - تنسيق التاريخ ، ( المزيد عن التنسيقات ).dateModify ($ date، $ format) التاريخ - قم بتغيير التاريخ ، مناسب للاستخدام مع التنسيقات النسبية .توليد بيانات اختبار عشوائي:
Faker \ integer ($ min، $ max) Number - عدد صحيح عشوائي من $ min إلى $ max بما في ذلكFaker \ ipv4 () سلسلة - عشوائي IPv4Faker \ arrayElement (صفيف $) سلسلة - عنصر عشوائي من الصفيفFaker \ name () String - اسم عشوائيFaker \ email () سلسلة - بريد إلكتروني عشوائيالآن لا يوجد العديد من الوظائف المضمنة. أضفت فقط ما يبدو لي أنه ضروري عند الاختبار. يمكنك إضافة ميزات جديدة حسب الحاجة في الإصدارات الجديدة. وفي المستقبل ، إذا كان ذلك مطلوبًا ، سأضيف القدرة على إنشاء وظائف مرتبطة ديناميكيًا يتم تنفيذها كطبقات خاصة في PHP.حالات الاختبار
حالة الاختبار هي سلسلة من العبارات التي يمكن تسميتها كوحدة. بعض التناظرية للإجراء في لغات البرمجة.يتم إنشاء حالة اختبار بواسطة عبارة testcase ، متبوعًا باسم حالة الاختبار ، مع بناء جملة مشابه لأسماء طريقة API . يحظر حالات الاختبار المتداخلة. testcase Registration $device
يمكن لبيان التشغيل استدعاء حالة اختبار منفصلة ، أو جميع حالات الاختبار التي لا تتطلب الحجج. run Get all users
فكرة مثل هذا الإطلاق هو أنه يمكن استخدام حالات الاختبار كاختبارات مستقلة منفصلة لجزء من منطق الأعمال وكإجراءات لتجنب تكرار التعليمات البرمجية في سيناريوهات الاختبار المعقدة.يتم تمرير الوسيطات إلى حالة الاختبار حسب المرجع أو بالقيمة في القياس الكامل لتمرير الوسائط إلى أساليب API.المتغيرات والمجالات
الأسماء المتغيرة حساسة لحالة الأحرف وتبدأ بعلامة $ (نعم ، نعم ، أنا pshpshnik).إذا كان نوع متغير صفيف ، ثم يتم إنتاج الوصول إلى الحقول الفردية أو عناصر قيمة من خلال هذه النقطة: $users.12.password
. بين النقاط ، يُسمح فقط بالأرقام أو الأحرف اللاتينية والشرطات السفلية والأرقام بالحرف اللاتيني الأول. أسماء الحقول حساسة لحالة الأحرف أيضًا.يمكن الوصول الديناميكي إلى عنصر صفيف:$post.comments[$i + 1].content
هناك أربعة أنواع من السياقات - نطاق المتغيرات.السياق العام - الذي تم إنشاؤه في البداية ، يحتوي على جميع المتغيرات المعلنة عند تنفيذ العبارات خارج حالات الاختبار واستدعاءات أسلوب API الخارجية.سياق حالة الاختبار - يتم إنشاء سياق جديد في كل مرة يتم فيها تنفيذ حالة الاختبار باستخدام عبارة التشغيل .في سياق أسلوب API يتم إنشاؤه عند استدعاء الأسلوب API، عندما مشغلي المذكورة في الأقسام - قبل و ما بعد .سياق المولد- لا توجد إمكانية في المولدات لإنشاء متغيرات جديدة أو تغيير المتغيرات الحالية ، وبالتالي تكون متغيرات وسيطات السياق العالمية للقراءة فقط. يتم تمرير المتغيرات دائمًا بالقيمة إلى سياق المولد.ملاحظة مهمة. في جميع السياقات ، تكون متغيرات السياق العامة متاحة إذا لم يتم إنشاء أسمائها في السياق الحالي.أمثلة على عوامل التشغيل للعمل مع المتغيرات: const $a = 1 let $a = 2
let $a = 1; $a = $a + 1; $a = $a + 2 print $a
Testcase Context example changes $argument1, $argument2 and $argument3 var $a = "changed" let $b = "changed" const $c = "changed" import $i let $i = "changed" var $argument1 = "changed" var $argument2 = "changed" var $argument3 = "changed"
اكتب النظام والعمليات
يتم استخدام الكتابة الديناميكية التراخي.يتم تخزين القيم في أغلفة على أنواع PHP المقابلة. لفهم أفضل ، راجع نظام نوع PHP. لقد جعلت حرية أقل قليلاً في تحويل النوع الديناميكي. على سبيل المثال ، عند إضافة سلسلة ورقم "2" + 2
، سيتم إنشاء خطأ ، وسيقوم PHP بإجراء الإضافة بهدوء. ربما سأحتاج إلى مراجعة قواعد الكتابة الديناميكية في المستقبل ، ولكن حتى الآن حاولت إيجاد توازن بين الراحة والدقة المطلوبة للاختبارات الموثوقة.أنواع البيانات المتوفرة في PieceofScript:Numberهو رقم. لأسباب تتعلق بالبساطة ، لم أصنع أنواعًا منفصلة لـ Integer و Float. الاختلاف الهام الوحيد بين الأعداد الصحيحة والأرقام الحقيقية في PieceofScript هو استخدام مصفوفة كمفاتيح: سيتم تقريب الأرقام الحقيقية إلى أعداد صحيحة.7 -42 3.14159
String - سلاسل محاطة بعلامات اقتباس مزدوجة ، من الممكن الهروب بشرطة مائلة"I say \"Hello world!\""
Null - التي تم تعيينها بواسطة قيمةnull
منطقية ثابتة غير حساسة لحالة الأحرف - هي نتيجة لعمليات منطقية وعمليات مقارنة ، يتم تعيينها بواسطة ثوابت غير حساسة لحالة الأحرفtrue false
التاريخ - التاريخ والوقت. "تحت غطاء المحرك" هو DateTime . يتم تحديد الثوابت في علامات الاقتباس المفردة بأحد التنسيقات .'now', '2008-08-07 18:11:31', 'last day of next month'
الصفيف عبارة عن صفيف ، وهو النوع الوحيد غير القياسي. لفصفيف . لا توجد أي حرف من هذا النوع ، ولكن يمكن أن تكون المصفوفات نتيجة لعمل المولدات ، أو الوظائف المضمنة (على سبيل المثال ، المصفوفة () - مرحبا PHP 5.3 وأدناه) ، أو يمكنك ببساطة الوصول إلى المفاتيح المتغيرة التي سيتم إنشاؤها ديناميكيًا عند التعيين. let $a.1 = 100 let $i = 1 let $a[$i + 1] = 200 let $a.sum = $a.1 + $a.2 print " "; $a.sum // 300 var $b = array(true, 3, $a, "Hi") // [true, 3, {1: 100, 2: 200, "sum":300}, "Hi"]
عند الوصول إلى متغير أو عنصر صفيف غير موجود ، سيتم إيقاف البرنامج النصي للاختبار وسيتم إنشاء خطأ. ولكن عند تنفيذ عبارات التأكيد أو يجب ، إذا تم الوصول إلى متغير غير موجود ، فلن يكون هناك خطأ ، ولكن سيتم اعتبار التحقق فاشل.التحقق من وجود ونوع متغير
يجب أن نذكر بشكل منفصل بناء التحقق من وجود ونوع المتغير @ .إذا تم تحديد @ في اسم المتغير بدلاً من $ ، فستكون نتيجة هذا البناء واحدة من:- سلسلة باسم نوع المتغير أو نوع عنصر المصفوفة ، إذا تم استخدام المفاتيح ؛
- قيمة خالية إذا لم يتم العثور على المتغير في سياقات يمكن الوصول إليها أو إذا كان العنصر بالمفتاح المحدد في الصفيف غير موجود.
يمكن أن يكون هذا التصميم مفيدًا عند التحقق من بنية استجابات HTTP. var $a.string_field = "Hello World" var $a.number_field = 3.14 var $a.bool_field = true var $a.date_field = '+1 day' var $a.null_field = null var $a.array_field = array(1, "2") assert @a.string_field == "String" assert @a.number_field == "Number" assert @a.bool_field == "Boolean" assert @a.date_field == "Date" assert @a.null_field == "Null" assert @a.array_field == "Array" assert @a.array_field.0 == "Number" assert @a.array_field.1 == "String" assert @a.array_field.2 == null assert @notExistedVar == null
أو في إنشاءات مثل: assert @comment.optional_field && $comment.optional_field > 20
تم تحسين العمليات المنطقية في أول معامل. إذا كان المعامل الأول غير صحيح ، فلن تحاول العملية && حتى حساب المعامل الثاني. وبالمثل مع || .
حفظ البيانات بين الجري
لقد استخدمت نصوصًا منفصلة ليس فقط للاختبار بعد الانتهاء من المهمة ، ولكن أيضًا أثناء التطوير. لقد قمت بتكملة البرنامج النصي وتغييره أثناء تنفيذ الميزة. في وقت لاحق ، أصبح هذا البرنامج النصي هو الأساس لكتابة حالة اختبار ، ولكن أثناء التطوير ، كان على المرء إجراء نفس مكالمات API مرارًا وتكرارًا. في الوقت نفسه ، في كل مرة في البرنامج النصي ، كان الوقت طويلًا لإنشاء كيانات جديدة من البداية (على سبيل المثال ، تسجيل المستخدم) ، وإنشاء القمامة في قاعدة البيانات والتدخل في كل شيء في التطوير. لذلك ، قررت أن أضيف القدرة على حفظ واستعادة قيم المتغيرات بين البدء في تخزين القيمة الرئيسية.يتم تمكين الحفظ بواسطة خيار سطر الأوامر --storage ، الذي يقوم بتعيين اسم ملف التخزين: pos.phar run ./start.pos --storage=storage.yaml
يتم حفظ البيانات بتنسيق YAML ، مما يجعل من السهل قراءتها وتحريرها.storage \ get (مفتاح $ $ ، $ defaultValue ، boolean $ saveValue = true) - إذا لم يكن المفتاح $ موجودًا أو لم يتم تحديد ملف التخزين ، فسوف تُرجع $ defaultValue. وإلا ، فإنها تُرجع القيمة المخزنة. إذا كانت الوسيطة $ saveValue صحيحة ولم يتم العثور على المفتاح $ key ، فسيتم كتابة $ defaultValue هناك.storage \ set (مفتاح $ $ ، $ value) - يحفظ القيمة $ باستخدام المفتاح $ key ، ويعيد القيمة $. إذا لم يتم تعيين ملف التخزين ، فإنه ببساطة إرجاع القيمة $.تخزين \ مفتاح (سلسلة $ regexp = خالية) صفيف- يعيد مجموعة من جميع المفاتيح المتاحة. إذا كانت الوسيطة $ regexp ليست فارغة ، فسيتم إرجاع المفاتيح المقابلة لهذا التعبير العادي. إذا لم يتم تعيين ملف التخزين ، فإنه يقوم بإرجاع صفيف فارغ.الإخراج إلى stdout
يمكن لـ PieceofScript إنشاء تقارير بتنسيق JUnit و HTML. الأول مطلوب للتكامل مع أنظمة CI / CD ، على سبيل المثال Jenkins. والثاني هو أن ترى بسهولة نتائج الاختبار بنفسك ، على سبيل المثال ، عند الاختبار محليًا. يمكن تعيين ملفات التقرير عند بدء التشغيل: pos.phar run ./start.pos --junit=junit_report.xml --html=report.html
مثال لتقرير HTMLيتم عرض معلومات مختلفة حول عمل المترجم في stdout. هناك 5 مستويات قياسية من إخراج المعلومات. كل ما يتم عرضه على نفس المستوى يتم عرضه أيضًا على الآخرين "الأكثر ثرثرة".هادئ - يتم تعيين المستوى الأكثر "صامتًا" بواسطة خيار سطر الأوامر -q .في هذا المستوى ، لا يوجد شيء يتم إخراجه حتى أخطاء المترجم الخطيرة. ولكن من خلال رمز الإرجاع غير الصفري ، يمكنك أن تفهم أن هناك خطأ ما.عادي هو المستوى الافتراضي ، بدون تحديد خيارات.على هذا المستوى ، يتم إنشاء أخطاء في المترجم. طلبات فشل الأساليب API وتجربة فاشلة ASSERT و لا بد منه .مطوّل - مُحدد حسب الخيار-v .في هذا المستوى ، يتم عرض نتائج بيان الطباعة .مطول للغاية - تم تعيينه بواسطة الخيار -vv .في هذا المستوى ، يتم عرض تحذيرات المترجم.تصحيح - تم تعيينه بواسطة خيار -vvv .في هذا المستوى ، يتم عرض جميع أسطر البرامج النصية التي يتم تنفيذها. جميع الطلبات والردود وطرق API، ونتائج جميع عمليات التفتيش تؤكد و لا بد منه .أمثلة
المثل "من الأفضل أن ترى مرة واحدة من أن تسمع مائة مرة" صحيح وفي تفسير "من الأفضل أن ترى الكود مرة واحدة من أن تقرأ وصفه مائة مرة". لقد أعددت وأمثلت الأمثلة في https://github.com/maximw/PosExamples مستودع .فايروستال
Virustotal.com - خدمة لفحص الملفات والروابط الضارة. وثائق API . يتم إجراء الاختبارات للجزء العام من API ، باستثناء طرق التعليق ، لأنه لا أريد أن أتردد في واجهة برمجة التطبيقات "القتالية" الحقيقية ببيانات الاختبار.للوصول إلى واجهة برمجة التطبيقات ، تحتاج إلى التسجيل والحصول على المفتاح وإضافته إلى ملف Virustotal / globals.pos .الاختبارات الجارية: pos.phar run ./Virustotal/start.pos
تشي هناك ل exe-shnik تكمن في مستودع؟لإجراء الاختبارات ، قمت بنسخ hiddeninput.exe من مكون وحدة التحكم في مستودع Symfony. يمكن حذف هذا الملف ، وللاختبارات استخدام أي حجم آخر يصل إلى 32 ميغابايت.
المعجنات
التناظرية Pasebin. وثائق API .للوصول إلى واجهة برمجة التطبيقات ، تحتاج إلى التسجيل ، والحصول على المفتاح وإضافته إلى ملف Pastery / globals.pos .الاختبارات الجارية: pos.phar run ./Pastery/start.pos
يشار إلى أنه مع هذه الاختبارات تم العثور على خلل في الحد الأقصى لعدد المشاهدات. تم إصلاحه بالفعل من قبل مطوري Pastery.ريك ومورتي
أعتقد أن هذه السلسلة المتحركة معروفة للكثيرين ، ويحبها الكثيرون. وثائق API . يتكون API من ثلاثة أقسام متطابقة تقريبًا الشخصية والموقع والحلقة. لذلك ، فإن السيناريوهات هي نفسها تقريبًا ، والاطلاع فقط على حالات الاختبار هو أحد الأقسام فقط.الاختبارات الجارية: pos.phar run ./RickAndMorty/20MinutesTest.pos
إذا كنت تعرف واجهة برمجة تطبيقات عامة قد تكون مثيرة للاهتمام للاختبار بهذه الطريقة ، فيرجى الكتابة في بريد إلكتروني شخصي.التعليقات والخطط للمستقبل إن وجدت
0) لدي قائمة بالتحسينات الصغيرة والكبيرة التي لست بحاجة إليها بعد ، ولكن يمكن أن تكون مفيدة.عرض القائمة- إضافة تقرير عن العمل بتنسيق Json مع إمكانية الكتابة فوقه بعد تشغيل البرنامج النصي عدة
- body replace remove
- , YAML
- HTTP- ,
- , run . .
- HTML- stdout, -vvv
- https
- application/x-www-form-urlencoded CURLFile . Guzzle 6,
- « »,
- API,
- HTML-, bootstrap- « », .
1) للتحقق من صحة النماذج في الردود API باستخدام مولدات لديها حتى الآن سوى وظيفتين - المعلنين اختر مماثلة () و متطابقة () . المصادقة معهم "خرقاء للغاية". بالطبع ، من الممكن بالفعل التحقق من الإجابات "يدويًا" ، وفي بعض الحالات لا يمكن ذلك بأي طريقة أخرى ، لكنني أريد أن أجعلها أكثر ملاءمة ، وحيثما أمكن ، تجنب التحقق من الإجابة يدويًا. هناك بعض الأفكار حول كيفية جعل إنشاء النماذج والتحقق من صحتها باستخدام نفس وصف النموذج ، وتجنب الازدواجية. ولكن حتى الآن لم يتم تشكيل هذه الأفكار بما فيه الكفاية بحيث يمكنك تنفيذها في التعليمات البرمجية.2) أعتقد أنها ستكون فرصة مفيدة جدا للسقالات أساليب API على أساس الوصف في OpenAPI ( التبختر )، الرمل ، ومجموعاتساعي البريد . ولكن هذا عمل كثير يستحق الجلوس إذا كان PieceofScript يستحق ذلك.3) سيكون من الجيد إنشاء مكونات إضافية لبعض IDEs ، مع تمييز الكود والإكمال التلقائي. سيكون الإكمال التلقائي لأسماء حالات الاختبار ، وطرق واجهة برمجة التطبيقات (API) ، والمشغلين والمتغيرات أمرًا سهلاً للغاية. لكنه لم "حفر" في هذا الاتجاه حتى الآن. فهم إنشاء تمييز لنص Sublime وبروتوكول خادم اللغة . سأكون سعيدًا إذا كان هناك أشخاص لديهم نفس التفكير ضليعين بالفعل في مثل هذه الأشياء.4) لا أعرف ما هي الأولوية لوضع القدرة على إنشاء وظائف مرتبطة ديناميكيًانفذت في PHP. من ناحية ، كل شيء بسيط هناك ، يكفي التعامل مع التحميل التلقائي وتحديد مواصفات الفئات ومساحات الأسماء المستخدمة. من ناحية أخرى ، ستؤدي الوظائف المعقدة مع تبعياتها حتمًا إلى تعارض في مساحة الاسم بين التبعيات (في أسوأ الحالات ، إصدارات مختلفة). هناك أيضا شيء للتفكير فيه.5) تقوم أنظمة الاختبار الجيدة بإجراء اختبارات مستقلة بالتوازي. الآن يمكن القيام بذلك عن طريق تشغيل المترجم عدة مرات بملفات بدء مختلفة ، حيث يتم توصيل حالات اختبار مختلفة. ولكن أعتقد أننا بحاجة إلى تضمين هذا في المترجم نفسه مع الكشف التلقائي عما يمكن إطلاقه بالتوازي.PS من ناحية ، بما أن هذه "حِرفي" ، سيكون من المنطقي وضع منشور في المحور "أنا PR". من ناحية أخرى ، أنا لا أقوم بالعلاقات العامة ، ولا أسعى لتحقيق أي مكاسب تجارية ، مجرد أداة صنعتها لنفسي ، قررت "تمشيط" ونشرها علنًا.