جميع الأنشطة

يتم تحديث محتوى هذا السجل تلقائيا   

  1. اليوم
  2. السلام عليكم ورحمة الله ممكن احد يحدد لي مشكلة الاتصال فين؟ قاعدة البيانات كالتالي: ALTER TABLE `ds_news` `id`, `news_title`, `news_img`, `news_txt`, `news_display`, `news_views`, `news_likes`, `news_share` وشكرا جزيلا ds.rar
  3. رائعة جدا لكن ممكن تعطينا فكرة عن اسعارها؟ وكيف تم عملية التسعير؟ وشكرا
  4. أمس
  5. مبدع استفدت كثير منك 😍

  6. الاسبوع الماضي
  7. وصلت الى مشكلة ما قدرت استخدمه في ionic ! هل فيه اضافة متناسقة مع ionic framework؟ وشكرا
  8. هنا موجود ديمو مستخدم ng-twitter ممكن يفيدك https://darul75.github.io/ng-twitter/
  9. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته أهلا و سهلا بكم اخواني الأعزاء، في هذه المقالة سنتطرق الى أسلوب ماتع في طريقة التحقق من نوع البيانات (PropTypes) في مكتبة React و React Native، اذا كنت جديداً معنا أنصحك بالعودة الى دروس سابقة لنمشي بخطوات مبسطة لنكمل المسيرة مع بعض و تكون فاهماً لهذه المقالة بحول الله. المقالات السابقة: عند بداية بنائك لتطبيقك أيا كان نوعه تطبيق ويب أو تطبيق موبايل، عادة ما نرسل بيانات معينة عبر (props) أو نطلب من المستخدم ادخال بعض المعلومات، تواجهنا بعض المشاكل و تكثر لدينا (Bugs) في تطبيقنا بسبب أننا لا نتحقق من نوع المعلومات المدخلة، فمثلاً: لو طلبنا من مستخدمنا ادخال رقم الهاتف و أخطأ أو تعمّد ادخال أحرف لاتينية/عربية! خطا فادح في برمجيتك ان كنت لا تتحق من صحة المعلومات : هل هي نصيّة؟ أم رقميّة؟ هل هو كائن؟ هل المعلومة مطلوبة؟ فما بالك بانشاء مشاريع كبيرة جداً كل مهمّاتها معلومات المستخدمين و وثائقهم و تحتفظ في قاعدة بيانات ضخمة! . لا يخفى على أحد أن جميع لغات البرمجة تحوي دوال التحقق و هذا ما يجب أن يكون فعلاً، كذلك مكتبة React تحوي مكتبة جزئية خاصة فقط بالتحققات و ستدعيها كلما دعت الحاجة لذلك. تسمى هذه المكتبة و الوظيفة في نفس الوقت بـ PropTypes . دعونا عبر مثال تطبيقي نطبّق خاصية التحقق من نوع البيانات بعدها نشرح كل جزئية على حدى: لنستفيد من مكتبة التحقق علينا استدعاؤها في تطبيقنا كالتالي: import PropTypes from 'prop-types'; // for reactjs web apps - import { PropTypes } from 'react'; //for react native نبني مثال بسيط تطبيق ويب يعرض جميلة بتنسيق H1 فيها كملة أهلاً، ثم يُرفق معها اسم معين عبر (props). نحن الآن هدفنا أن نتحقق من البيانات التي يود أن يدخلها المستخدم. import PropTypes from 'prop-types'; class Greeting extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } Greeting.propTypes = { name: PropTypes.string }; لاحظ أننا أضفنا التحقق بأسفل الكلاس و خارج قوسيه المعكوفتين، (ينبغي أن تعرف أننا نكتب بصيغة ES6 لا ES5 القديم). Greeting.propTypes = { name: PropTypes.string }; اذا، يجب علينا ارفاق اسم الكلاس (Class) تتبعه كلمة (.propTypes) بعدها نفتح قوسين معكوفتين: ندخل اسم المتغير الذي يحمل البيانات - في مثالنا هذا : name. نرفق بعده نوع الصيغة التي تودها، في مثالنا هذا .. البيانات نصيّة لا غير PropTypes.string و string تعني نصيّة. يمكننا أن نخبر أن برنامجنا أن هذه المعلومة مطلوبة (Required) و يجب حتما ادخالها و لاتبقى فارغة عبر الوظيفة isRequired لتصبح كالتالي: Greeting.propTypes = { name: PropTypes.string.isRequired }; و هناك أنوع كثيرة من صيغ التحقق كـ: • PropTypes.array // مصفوفة • PropTypes.bool // منطقية • PropTypes.func // وظيفة • PropTypes.number // رقم • PropTypes.object // كائن • PropTypes.string // نص نصل الى نهاية درس اليوم، أي استفسار أو جملة مبهمة لا يردكم الكيبورد نحن متواجون باذن الله للرد على استفساراتكم. دعواتكم لنا.
  10. شكرا الله يعطيك العافية جاري التجربة
  11. نعم يوجد https://www.npmjs.com/package/ng4-twitter-timeline
  12. السلام عليكم ورحمة الله هل يوجد بلقن خاص بعرض هاشتاق محدد في تويتر على كوردوفا او اي منصة؟ اريد عرضها في برنامج مصمم بالانقولار 4 وشكرا
  13. نحتاج أمثلة لفهم الفكرة
  14. بدايةً يجب عليك التوجه الى Facebook Developers والتسجيل كمطور عبر حسابك الشخصي في فيسبوك وذلك بالضغط على Register بعد ذلك نختار Yes ثم Register ثم Create App ID بعد ذلك نضع اسم التطبيق والإيميل الخاص بك سيتم إنشاء تطبيق Facebook خاص بك وسيعطيك APP ID الذي سنحتاجه لاحقاً ثم اضغط على Get Started لنبدأ بتجهيز المشروع ثم نختار Android ستظهر لنا هذه الخطوات نبدأ أولاً بإنشاء مشروع جديد على Android Studio وعلى Firebase ونضيف مكتبةFirebase Auth compile 'com.google.firebase:firebase-auth:10.2.1' ونقوم بربط Firebase ب مشروع Android بعد ذلك نقوم بإضافة Facebook SDK ,ولذلك علينا إضافة mavenCentral قبل dependencies repositories { mavenCentral() } ثم نضيف Facebook SDK في dependencies ثم نعمل Sync ل Gradle compile 'com.facebook.android:facebook-android-sdk:[4,5)' بعد ذلك ننتقل الى الخطوة الثالثة ونضيف اسم package الخاص بمشروع الأندرويد ونضيف اسم الأكتفتي الإفتراضي الذي سيعمل في التطبيق ,في حالتي هو MainActivity ونضيف قبله اسم package ثم . واسم الأكتفتي بعد ذلك ستظهر لك رسالة تحذير بأنه لا يوجد تطبيق بهذا الاسم موجود على متجر Google Play Store,لا عليك اختر Use this package name بعد ذلك سنحتاج الى معرف يدعى Key Hash ولتوليد هذا المعرف يمكنك إما نسخ الأمر الموجود في Facebook Quick Start أو يمكنك إستخدام هذه الأداة التي صنعتها لتسهيل الموضوع ومتوفرة لأنظمة 32 و 64 بت, فقط قم بتشغيل الملف التنفيذي وإختر نوع الKey Hash (هل تريد صنعه ل Debug أم ل Release) عند تشغيل ملف Debug سيطلب منا رمز Keystore قم بإدخال أي رقم أو قم بكتابة android فهي الكلمة الإفتراضية أما عند تشغيل ملف Release فسيطلب منك رمز Alias الذي وضعته عند إنشاء ملف الشهادة الذي ينتهي بصيغة jks (عند عمل Generate Signed APK في الأندرويد ستوديو) ثم سيطلب منك مسار ملف الشهادة (C:User\Desktop\Cert.jks) على سبيل المثال وسيظهر لك ال Key Hash قم بنسخه والصقه في Facebook ثم قم بتفعيل Single Sign On بعد ذلك سنضيف بعد الأمور في Android Studio نقوم بنسخ App ID ونلصقه في ملف strings.xml بعد ذلك نضيف صلاحيات الإنترنت في Android Manifest <uses-permission android:name="android.permission.INTERNET"/> ثم نضيف Meta-Data قبل إغلاق وسم application <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/> ثم نضيف أكتفتي المسؤولة عن تسجيل الدخول من Facebook (موجودة ضمن Facebook SDK) <activity android:name="com.facebook.FacebookActivity" android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:label="@string/app_name" /> ونضيف أكتفتي أخرى في حال كان المستخدم لم يقم بتثبيت تطبيق Facebook في جهازه وهي موجودة ضمن Facebook SDK أيضاً <activity android:name="com.facebook.CustomTabActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="@string/fb_login_protocol_scheme" /> </intent-filter> </activity> ونضيف Protocol Scheme في strings.xml (نقوم بنسخه من Facebook Quick Start Guide) الآن نتجه لى activity_main.xml ونضيف زر تسجيل الدخول ثم نتجه الى MainActivity ونعرف بعض المتغيرات FirebaseAuth LoginButton زر تسجيل الدخول CallbackManager المسؤول عن إعادة نتيجة تسجيل الدخول ثم قمنا بإعطائهم قيم في onCreate ثم جعلنا زر LoginButton يقرأ صلاحيات Email بعد ذلك قم بتسجيل Callback عبر ميثود registerCallback وأعطيناه callbackManager كبارامتر وهي تعيد لنا 3 ميثود onSuccess عند نجاح عملية تسجيل الدخول onCancel عند الغاء عملية التسجيل من قبل المستخدم onError عند حدوث خطأ ما وقمنا بعمل Log في كل حالة ثم قمنا بعمل Override ل onActivityResult وقمنا بتسجيل callbackManager في onActivityResult (بدونه لن تعود أي نتيجة ) أما الآن سنقوم بإنشاء ميثود handleFacebookAccessToken التي تقوم بأخذ Access Token من ميثود onSuccess عبر loginResult ونقوم باستدعاء ميثود mAuth.signInWithCredential لحفظ المستخدم في Firebase وقمنا بعمل Log للنتيجة ثم استدعينا الميثود في onSuccess وقمنا بأخذ AccessToken الآن يجب علينا الحصول على App Secret و App Id قم بالتوجه الى إعدادات تطبيق Facebook الى Dashboard وستجد App Secret و App Id قم بنسخهم ثم توجه الى Firebase Console وقم بتفعيل تسجيل الدخول عبر Facebook والصق App Id و App Secret ثم نقوم بنسخ OAuth Uri ثم Save بعد ذلك نتوجه الى إعدادات Facebook Login ونضع OAuth Uri نجرب تشغيل التطبيق وعند الضغط على زر Login ,اذا كان المستخدم لم يثبت تطبيق Facebook فسيظهر له بهذا الشكل أما اذا قام بتثبيته فسيظهر بهذا الشكل عموماً نجرب التشغيل وعند نجاح العملية ستجد أن المستخدم قد تم تسجيله في Firebase وسيتغير نص الزر الى Log out اذا كنت قد جربت عملية تسجيل الدخول على نفس حساب المطور فستنجح عملية التسجيل,أما اذا قمت بتجريبه على حساب آخر غالباً ستفشل عملية التسجيل وذلك لأنه التطبيق الذي أنشأته ليس Public ولحل هذه المشكلة قم بالتوجه الى إعدادات التطبيق في Facebook في قسم App Review ونقوم بجعله Public رابط المشروع على Github ملاحظة:المشروع على Github للمعاينة فقط ولايمكنك تجربته على Android Studio لعدم وجود google-services.json الخاص بك
  15. السلام عليكم ورحمة الله وبركاته، مساء الخير.. عندي جدول لسجلات يومية للطلاب، لكن المدخلات عندنا فيها تغييرات بحسب انتماء الطالب لفئته. كذلك: سجل يوم الأحد، تسجل فيه معلومات مختلفة، عن يوم الاثنين والمعلومات المختلفة هذه كمثال: المواظبة: حاضر، متأخر، غائب وفيه معلومات لها احتمالين فقط ! والـ HTML FORM راح يختلف باختلاف فئة الطالب، وبإختلاف اليوم، فكيف نضبط أمر السجلات اليومية في هيكلة ثابتة، بحيث وقت إحصاء البيانات لا يحدث مشاكل. فكرتي: هو جعل هذا الصف في السجلات اليومية عبارة عن مصفوفة JSON، وبهذا تحل المشكلة. بقيت مشكلة: فئة الطالب، لها خانات مختلفة، يعني في الـ HTML FORM : مرات بيكون مدخل يحتمل 3 خانات، ومرات بيكون مدخل يحتمل اجابتين، إلخ. أنا فكرت كالتالي: يكون فيه جدول لأنواع المدخلات اليومية، ويكون فيه جدول للفئات المختلفة، الفئة ترتبط بعدد من أنواع المدخلات، والمدخلات ترتبط بعدد من الفئات، علاقة Many-Many هل من أفكار مساعدة لهيكلة قواعد البيانات؟ laravel/php
  16. Earlier
  17. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته أهلا و سهلا بكم اخواني الأعزاء، في هذه المقالة سنتطرق الى انشاء عارضة القوائم (ListView) في تطبيقات React Native، اذا كنت جديداً معنا أنصحك بالعودة الى دروس سابقة لنمشي بخطوات مبسطة لنكمل المسيرة مع بعض و تكون فاهماً لهذه المقالة بحول الله. المقالات السابقة: لو تفحصت في توثيقات React Native على موقعهم الرسمي تجد مكوناً أساسيا (core component) يسمى بـ ListView ، هذا الأخير يمكّنك من انشاء قائمة تمرير عمودية تظهر بها معلوماتك التي تجلبها من قاعدة البيانات أو معلوماتك معينة في مصفوفة (Arrays). معلومة: هذا المكونّ ليس وحده ضمن اطار React Native بل توجد مكونات أخرى تؤدي تقريباً نفس العمل كـ FlatList أو SectionList كلاهما يحمل أسلوباً مختلفا في كتابته لانشاء هذا العنصر يتوجب علينا برمجة (data source) أو مصدر بيانات و ملئِه بمصفوفة من الخصائص؛ لتكون مصدرا لبياناتها التي سنعرضها بعد قليل و نمررها بدالة أخرى تعرف بـ renderRow الى JSX. class List extends Component { constructor (props) { super (props); const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }); this.state = { dataSource: ds.cloneWithRows(['row 1', 'row 2']) }; } render () { return ( <ListView dataSource = { this.state.dataSource } renderRow = { (rowData) => <Text> { rowData } </Text> } /> ); } } لنرى بقرب ماذا كتبنا: أنشأنا دالة بناء (constructor) و عرّفنا معها super كما أخبرتكم سابقاً أنها إلزامية جداً في صيغ (ES6). و ضمن دالة البناء أنشأنا نموذجاً : عارض مصدر بيانات القائمة (ListViewDataSource) و هذا العارض يحمل محددات (parameter) و أسس (argument) هي أربع: getRowData(dataBlob, sectionID, rowID) getSectionHeaderData(dataBlob, sectionID) rowHasChanged(previousRowData, nextRowData) sectionHeaderHasChanged(previousSectionData, nextSectionData) 1 - المحدد الأول (getRowData) : وظيفة تقوم بجلب البيانات المطلوبة (data required) لتعيدها الى الصف (Row). بامكانك تخصيصها لتعيد و تمرر ما تشاء الى العارض (ListViewDataSource) و لا يهم ان كتبتها في شفرتك أو لا .. لأنها تكون معرفة افتراضياً اذا كنت لا تحتاجها. 2 - المحدد الثاني (getSectionHeaderData) : وظيفة تقبل كذلك نقطة بيانات (blob of data) و قسمها الخاص (section ID) لتعيد فقط البيانات المطلوبة الى (section header). و لا يهم ان كتبتها في شفرتك أو لا .. لأنها تكون معرفة افتراضياً اذا كنت لا تحتاجها. 3 - المحدد الثالث (rowHasChanged) : هي وظيفة بمثابة تحسين الأداء، مصممة فقط لتعيد التقديم (re-render) الى الصفوف التي تم تغيير بيانات مصدرها. مختلفة عن المحددات السابقة (getRowData) و (getSectionHeaderData). مهمة للغاية و يجب عليك كتابتها ضمن العارض. 4 - المحدد الرابع (sectionHeaderHasChanged) : وظيفة اختيارية، تقارن (section headers) التي تحتاج الى اعادة تقديم (re-render). اذاً، أنشأنا حالة (State) أسميناها (dataSource) و استدعينا cloneWithRows الذي يحمل متغيرين - (dataBlob) : المعلومات التي تود تمريرها للعارض و (rowIdentities): هي اختيارية. لا تنسى (dataSource) الحاملة للمعلومات غير قابلة للتغيير. نعود مرة أخرى للمكوّن نفسه (ListView) و نمرر له البيانات التي أنشأناها مسبقاً: عبر (renderRow) التي تأخذ المعلومات من (dataSource) الأولية و تمررها الى (dataSource) الثانية في JSX. ما رأيك الآن، جميلة صح! طريقة سهلة و بسيطة لعرض قوائمك بسهولة. ان شاء الله تكون استمتعت بالدرس، أي استفسار أو جملة مبهمة لا يردكم الكيبورد نحن متواجون باذن الله للرد على استفساراتكم. دعواتكم لنا.
  18. السلام عليكم و رحمة الله، اليوم معنا درس جديد في سلسلة أسميتها (React Native .. تعلمها معنا في عالم البرمجة)، و كما أشرت سابقاً قد كتبت مقالين حول مكتبة رياكت أشرح فيها الأساسيات المهمة لكل مبتدئ .. ننتقل الآن لنبدأ درسنا في رياكت نيتف باللغة العربية، مع أول شرح في بعنوان ( ورقة الأنماط StyleSheet ) لنبدأ على بركة الله: تقبل مكونات الواجهة في React Native استدعاء خاصية تسمى بـ الأنماط (style) تحوي اسما (name) وقيمة (value) تشبه الى حد ورقة الأنماط في ترميز CSS StyleSheets مع استثناء واحد هو أنها أسماء تعريفها لا تحوي وجود مسافات أو علامات ترقيم أو علامة (-) كتضمين Css في شفرات الجافاسكربت . فمثلاً، في خصائص CSS نجد تسمية : border-radius لكن اذا ما نقلناها الى رياكت نيتف تصبح: borderRadius مع ملاحظة الحرف الكبير لكلمة Radius. لاستخدام و قراءة الأنماط في رياكت نيتف، يجب عليك تضمين مكون StyleSheet في رأس الملف الذي تحرره ليكون بامكانك التعامل معه بكل اريحية بأسلوب (render) . import { AppRegistry, StyleSheet, Text, View } from 'react-native'; دعونا نلقي نظرة حول أنواع تضمين ملفات الأنماط مع/ و خاج ملفات الجافسكربت: (هذه الشفرات الصغيرة هي للشرح فقط، نفسها نفس حال كتابتها في مشاريعك البرمجية) الأنماط المضمنة (Inline styles) النمط المضمن هو أسلوب يتم تعريفه ضمن شفراتك البرمجية الخاصة بك مباشرة داخل نفس المكوّن (Component) كإدراجك للنمط داخل تعليمات HTML. class Tasks extends Component { render () { return ( <View style = {{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' }}> <Text style = {{ fontSize: 20, textAlign: 'center', margin: 10 }}> Welcome to React Native! </Text> </View> ) } } كما ترى في في الشفرة السابقة، اضفنا التنسيقات لكن شفرتنا أصبحت غير واضحة تماماً و صعب قراءتها بسهولة و تحليلها. ماذا لو قمنا تضمين تنسيقات كبيرة و متعددة! هل سيصبح بامكانك تعديلها بسرعة! اذا دعونا لنستعمل أسلوبا مختلفاً في تحرير الأنماط خارج المكونات الرئيسة و شفراتك البرمجية داخل نفس الملف. أسلوب (StyleSheet)، في نفس الملف class Tasks extends Component { render () { return ( <View style = { styles.container }> <Text style = { styles.welcome }> Welcome to React Native! </Text> </View> ) } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' }, welcome: { fontSize: 20, textAlign: 'center', margin: 10 } )}; ماذا تلاحظ الآن، هذا أفضل بكثير من سابقه. قمنا بنقل أنماط المكون بعيدا عن شفراتك البرمجية و صنعنا له مرجعاً (reference) يقوم بتعريف تنسيقه دون الحاجة إلى إعادة كتابة نفس الأنماط المضمنة مراراً وتكراراً. و مع ذلك، فإن المشكلة التي نواجهها هو ملف طويل للغاية من تنسيقات قد تطول و تكبر كلما أضفنا مكونات أكبر و أكبر؛ هل سنضطر الى النزول للأسفل دائما لنعيد صياغة التنسيقات! لا طبعاً يمكننا استخدام أسلوب ثانٍ لنجعل تطبيقنا سهل التعديل و الاضافة عن طريق استيراد الملف لوحده. الأنماط (StyleSheet) كملف مستورد! قم بانشاء ملف .JS خاص و سمّه كما تشاء (styles.js): const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' }, welcome: { fontSize: 20, textAlign: 'center', margin: 10 } )}; export default styles; و استدعه في ملفك الرئيسي الخاص بالتطبيق كالآتي: import styles from './styles.js'; class Tasks extends Component { render(){ return ( <View style = { styles.container }> <Text style = { styles.welcome }> Welcome to React Native! </Text> </View> ) } } هذا أفضل بكثير من سابقيه. صح! جعلنا هذا التطبيق سهلا و بسيطا يقرؤه أي شخص و يفهمه دون الحاجة لتضييع الوقت. بعض النصائح: هناك بعض الأساليب لا يعرفها البعض في جعل مكونك الخاص يقبل عدة تنسيقات بنفس النمط، كأن مثلا تعرف text1 و text2 بحجمين مختلفين لكن لهما نفس اللون عن طريق المصفوفات (Array) export default class Tasks extends Component { render() { return ( <View> <Text style={styles.red}>just red</Text> <Text style={styles.bigblue}>just bigblue</Text> <Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text> <Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text> </View> ); } } const styles = StyleSheet.create({ bigblue: { color: 'blue', fontWeight: 'bold', fontSize: 30, }, red: { color: 'red', }, }); دائماً اجعل متغيراتك معرّفة باسم واضح سهلة القراءة. لا تضيع وقتك و أنت تائه بين الأسماء ان لم تكتبها بشكل جيد. نصل الى نهاية مقال اليوم، أي استفسار أو جملة مبهمة لا يردكم الكيبورد نحن متواجون باذن الله للرد على استفساراتكم. دعواتكم لنا.
  19. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذه المقالة سنتعلم كيفية استخدام الـ Parameterized (الدوال متعددة المدخلات) و Theories (النظريات وافتراضاتهم) للتحقق من مزيج للمدخلات المتعددة في دوال الاختبار, حتى لايصادف المشروع اي من الاخطاء المستقبليه بسبب مدخلات عشوائيه او شاذة للدوال. وبما انهم متشابهان في الوظيفة فأرى من الافضل التطرق لهم في مقالة واحدة. المواضيع السابقة (مهمة لفهم هذا المقال) هذه هي المقالات السابقة والتي تعتبر ضروريه لفهم هذا المقال فاذا لم تكن لديك خلفيه مع الـ JUnit انصحك بقرائتها قبل هذا الموضوع والذي يعتبر المقال السادس من اصل ستة مقالات والاخير في هذه السلسلة للإصدار الرابع من JUnit والذي يتوافق مع تطوير تطبيقات الاندرويد, اما بالنسبه للإصدار الخامس من الـ JUnit فهو مشابه للإصدار الرابع هذا مع اضافة بعض من الاشياء الجديده فقط. رابط المشروع https://github.com/mzdhr/KidCalculator-JUnit وتوجد كلاسات هذه المقالة باسم: ParameterizedTest.java و TheoriesTest.java في المشروع. واذا اردت الاطلاع على كلاس الـموديل فهذه هي Calculator.java. ماذا سوف تقرئ في هذه المقالة ماهو المقصود بالمدخلات والمخرجات للدالة؟ ماهي المعضلات التي تقوم الـ Parameterized و Theories بحلهم؟ كيفية استخدامهم؟ وماهي خطوات كتابة كلاساتهم؟ وماهو الفرق بينهم؟ وايضاً ماهي الفروقات بين دالة النظرية ودالة الاختبار. توضيح ماهي المدخلات للدالة؟ هي الـ Parameters للدالة. مثال للدالة public int addition(int firstNumber, int secondNumber) { return firstNumber + secondNumber; } مثال للمدخلات addition(3, 5); تعقيب الرقم ٣ والرقم ٥ يعتبران مدخلات للدالة. والناتج يعتبر المخرج لها. بعض من المعضلات التي تقوم الـ Parameterized و الـ Theories بحلهم هذه بعض من ابرز المشاكل او المعضلات التي تستطيع حلهم باستخدام الـ Parameterized و الـ Theories في الـ JUnit. ماذا لو اردت ان تقوم بكتابة اختبار لدالة الـ addition يحتوي على الكثير من المدخلات؟ هنا نستخدم الـ Parameterized. ماذا لو اردت التحقق من ان الناتج دائماً صحيح كما تريده لداله ما, حتى وان قمنا بشقلبة او مزج او خلط او عكس المدخلات مع بعضها البعض؟ هنا نستخدم الـ Theories. استخدام Parameterized في الـ JUnit نستخدم الـ Parameterized اذا اردنا اجراء اختبارات كثيرة على دالة ما, وهذه الاختبارات تختلف في المدخلات و المخرجات للدالة. معضله تخيل لو ان لديك الدالة التالية: public int addition(int firstNumber, int secondNumber) { return firstNumber + secondNumber; } وانك تريد ان تقوم بكتابة دالة اختبار تقوم بتجربة العديد من المدخلات عليها (ربما stream كامل من المدخلات وليس فقط لسته) لإختبار صحة منطقها. فالحل البدائي هو تكرار كتابة هذه الدالة بعدد المدخلات التي تريد تجربتهم عليها. اما الحل المناسب هو كتابة كلاس Parameterized تقوم بهذا العمل على اكمل وجهه. خطوات كتابة كلاس Parameterized لإختبار المدخلات و المخرجات المتعددة نقوم بعمل كلاس مشغل للـ Parameterized وذلك من خلال النوتيشن RunWith كما في حال المشغلات بالمقالة السابقة. نقوم بكتابة الـ Fields التي سوف نحتاجها في هذه الكلاس مثل عنصر من الموديل Calculator.java وايضاً عناصر ترمز للمدخلات والمخرجات. نكتب دالة setUp ذي النوتيشن Before, لتجهيز عناصرنا المراد اجراء الاختبارات عليهم. ننشئ Construction لربط عناصر الـ Fields بالقيم التي سوف ندخلها لاحقاً. ننشئ دالة data ونجعلها static تقوم بإرجاع المدخلات و المخرجات التي نريد اختبار الدالة بها, ونضع النوتيشن Parameterized.Parameters فوقها. الان نقوم بكتابة دالة الاختبار, والتي سوف تختبر الدالة addition من الموديل Calculator. ونستخدم القيم التي بالـ Fields كمدخلات و مخرجات لدالة الـ addtion. الكود لكلاس مشغل الـ Parameterized package com.company; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; // This class become a Parameterized Runner @RunWith(Parameterized.class) public class ParameterizedTest { // Fields private Calculator mCalculator; private int mInput01; // uses to store input for the first number. private int mInput02; // uses to store input for the second number. private int mExpect; // uses to store input for the expect test result. @Before public void setUp(){ // Arrange mCalculator = new Calculator("Orange"); } // Class Constructor -> To hook the values to our @Test Method. // It will run for each parameter we have in our Data. public ParameterizedTest(int input01, int input02, int expected){ mInput01 = input01; mInput02 = input02; mExpect = expected; } // This notation provide the input parameters for our @Test Method via the Constructor. @Parameterized.Parameters public static List<Object[]> data(){ return Arrays.asList(new Object[][]{ {2, 4, 6}, // means: 2 + 4 = 6 {4, 4, 8}, // means: 4 + 4 = 8 {-11, 4, -7}, // means: -11 + 4 = -7 {66, 395, 461}, // means: 66 + 395 = 461 {1000, -4, 996}, // means: 1000 + 4 = 996 {99, 1, 100} // means: 99 + 1 = 100 }); } // Our @Test Method @Test public void additions_test(){ // Action int result = mCalculator.addition(mInput01, mInput02); // first number + second number = result. // Assert assertEquals(result, mExpect); } } تعقيب قمنا بجعل هذه الكلاس تعمل كمشغل Parameterized وذلك من خلال استخدام النوتيشن RunWith اعلاها. ثم أنشأنا حقل لعنصر الموديل لدينا Calculator. وايضاً أنشأنا ثلاثة حقول وهي mInput01 و mInput02 و mExpect حتى نخزن فيهم قيمة المدخلات والمخرجات لاحقاً. و جهزنا مانريد في الدالة setUp ذي النوتيشن Before قبل بدء دالة الاختبار. ثم قمنا بانشاء Constructor للكلاس ياخد ثلاثة عناصر ويضع قيمتهم في الحقول الثلاثة السابقه. وبعد ذلك قمنا بكتابة دالة data تقوم بإرجاع لسته وبها جميع المدخلات والمخرجات التي نريد التحقق منهم ووضع النوتيشن Parameterized.Parameters فوقها, حتى تصبح هي المزود للـ Constructor والذي بدوره سوف يضع هذه القيم في الحقول الثلاثة في كل تشغيل له لكل احتمال. واخيراً قمنا بكتابة دالة الاختبار additions_test والتي سوف تختبر الدالة addition من الموديل Calculator بجميع المدخلات و المخرجات بلستة الدالة data. النتيجه تعقيب جميع الاختبارات التالية قد نجحت, اذن الدالة addtion لايوجد بها خلل. 2 + 4 = 6 4 + 4 = 8 -11 + 4 = -7 66 + 395 = 461 1000 + 4 = 996 99 + 1 = 100 وهكذا قمنا باختبار الكثير من المدخلات والمخرجات لدالة بكتابة دالة اختبار واحدة فقط. استخدام Theories في الـ JUnit نستخدم الـ Theories (النظريات) اذا اردنا حصر اي دالة في افتراضات (Assumptions) نحن نحددها, وشرط نجاح الاختبار هو ان تكون النتيجة دائماً صحيحة (اي true). فهي مشابهه جداً للـ Parameterized, ولكن الفرق هنا ان هذه تختلف في المدخلات فقط, وتتشابه في النتيجه وهي true في كل الاحوال. ماهي النظرية التي سوف نكتبها نظرية تقوم باخد مدخلين ثم تقوم بجمع فقط المدخلات الذي يكون الناتج لهم زوجي. خطوات كتابة كلاس Theories لإنشاء نظرية اختبار نقوم بعمل كلاس مشغل للـ Theories وذلك من خلال النوتيشن RunWith كما في حال المشغلات بالمقالة السابقة. نقوم بكتابة الـ Fields التي سوف نحتاجها في هذه الكلاس مثل عنصر من الموديل Calculator.java. نكتب دالة setUp ذي النوتيشن Before, لتجهيز عناصرنا المراد اجراء الاختبارات عليهم. ننشئ دالة data ونجعلها static تقوم بإرجاع المدخلات التي نريد اختبار الدالة بها, ونضع النوتيشن DataPoints فوقها. الان نقوم بكتابة النظرية (بالنوتيشن Theory وليس Test), والتي سوف تختبر ناتج فرضيات وتأكيدات نحن نريدها باستخدام الدالة addition من الموديل Calculator. الكود لكلاس مشغل الـ Theories package com.company; import org.junit.Before; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; import static org.junit.Assert.assertTrue; import static org.junit.Assume.*; // This class become Theories.class Runner. @RunWith(Theories.class) public class TheoriesTest { // Fields private Calculator mCalculator; @Before public void setUp(){ // Arrange mCalculator = new Calculator("Purple"); } // Our Data Points (the inputs) @DataPoints public static int[] data() { return new int[]{ 2, 6, 8, 7, 3, 0 }; } // Our @Theory Method, not a @Test @Theory public void addition_even_result_test(int value1, int value2){ // Assumptions -> assumeTrue(), assumeNotNull(), assumeNoException(), assumeThat(), etc... assumeTrue(value1 % 2 == 0); assumeTrue(value2 % 2 == 0); assumeTrue( value1 != 0); assumeTrue( value2 != 0); // Action int sumResult = mCalculator.addition(value1, value2); // Assert assertTrue( sumResult % 2 == 0); // Just for demonstration System.out.println(value1 + " + " + value2 + " = " + sumResult +" is even"); } } تعقيب قمنا بجعل هذه الكلاس تعمل كمشغل Theories وذلك من خلال استخدام النوتيشن RunWith اعلاها. ثم أنشأنا حقل لعنصر الموديل لدينا Calculator. وجهزنا مانريد في الدالة setUp ذي النوتيشن Before قبل بدء دالة النظرية. ثم قمنا بكتابة دالة data تقوم بإرجاع لسته وبها جميع المدخلات التي نريد التحقق منهم ووضع النوتيشن DataPoints فوقها, حتى تصبح هي المزود لدالة النظرية لدينا لاحقاً. واخيراً قمنا بكتابة دالة النظرية addition_even_result_test والتي سوف تختبر الدالة addition من الموديل Calculator لجميع من المدخلات بلستة الدالة data. النظرية تختلف عن الدالة في انها تستخدم النوتيشن Theory. ايضاً تختلف عن الدالة في انها تأخد مدخلات parameters. النظرية تأخد مدخلاتها (parameters) من الدالة data المعلمه بالنوتيشن DataPoints. تستطيع ايضاً استعمال Fields ولكن تعلمها بالنوتيشن DataPoint. النظرية في بدايتها نقوم بكتابة الافتراضيات وهي باستخدام دوال الـ assume التي تأتي مع الـ JUnit. ثم نقوم بكتابة الفعل ومن ثم التأكيد. ناتج تشغيل كلاس النظرية (لاحظ كيف ان النظرية تقوم بتجربة جميع الاحتمالات للمدخلات بمزج وخلط وعكس الـ DataPoints) 2 + 2 = 4 is even 2 + 6 = 8 is even 2 + 8 = 10 is even 6 + 2 = 8 is even 6 + 6 = 12 is even 6 + 8 = 14 is even 8 + 2 = 10 is even 8 + 6 = 14 is even 8 + 8 = 16 is even تعقيب لدينا البيانات التالية : 2, 6, 8, 7, 3, 0 التي سنستخدمهم داخل النظرية. وقمنا بكتابة فرضيات (باستخدام الـ assume) وهي: لنفرض ان المدخل الاول و المدخل الثاني لايساويان صفر, وايضاً لنفرض ان ناتج باقي القسمة للمدخل الاول والثاني يساوي صفر (لماذا؟ حتى نتأكد ان العدد هو رقم زوجي) هكذا: assumeTrue(value1 % 2 == 0); assumeTrue(value2 % 2 == 0); assumeTrue( value1 != 0); assumeTrue( value2 != 0); والان كل ماينطبق عليه هذه الشروط من DataPoints سوف تقوم النظرية باستخدامه في الفعل (addition), وعكس ذلك سوف تقوم بتجاهله. ونلاحظ انها تجاهلة الصفر والاعداد الفردية (كما هو ظاهر في ناتج تشغيلها بالسابق). // Action int sumResult = mCalculator.addition(value1, value2); ثم ستقوم النظرية بالتأكد هل ناتج الجمع هو زوجي. // Assert assertTrue( sumResult % 2 == 0); وهكذا توصلنا الى الاعداد الذي يكون ناتج الجمع لهم زوجي. والحمد لله تم الانتهاء من هذه السلسلة التي تعتبر مدخل مناسب لمن يريد الدخول في عالم الاختبارات في تطوير تطبيقات الاندرويد, والذي سوف اتطرق له ان شاء الله في المستقبل في مقالات اخرى.
  20. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذه المقالة سنتعلم كيفية استخدام الـ Suites و Categories للتحكم في تشغيل الاختبارات حتى يتمكن المبرمج من التحكم بشكل ادق في ادارة و تشغيل اي من الاختبارات كما يتطلب الوضع, وبما انهم متشابهان في الوظيفة فأرى من الافضل التطرق لهم في مقالة واحدة. المواضيع السابقة (مهمة لفهم هذا المقال) هذه هي المقالات السابقة والتي تعتبر ضروريه لفهم هذا المقال فاذا لم تكن لديك خلفيه مع الـ JUnit انصحك بقرائتها قبل هذا الموضوع والذي يعتبر المقال الخامس من اصل ستة مقالات. رابط المشروع https://github.com/mzdhr/KidCalculator-JUnit وتوجد كلاسات هذه المقالة باسم: AdditionTest.class و SubtractionTest.class و MultiplicationTest.class و DivisionTest.class و AllMathematicalTest.java و MathematicalSuiteCategoriesTest في المشروع. واذا اردت الاطلاع على كلاس الـموديل فهذه هي Calculator.java. ماذا سوف تقرئ في هذه المقالة متى تستخدم الـ Suite, وكيفية انشاء مشغل Suites؟ متى تستخدم الـ Category, وطريقة انشاء فئة Category, وكيفية انشاء مشغل Category؟ واخيراً ماهو الفرق بين الـ Suite و Category؟ استخدام Suites في الـ JUnit نستخدم الـ Suite اذا كانت لدينا الكثير من كلاسات الاختبارات ونريد تشغيلهم في اّن واحد. تخيل ان لديك ٥٠ كلاس اختبار (امر محتمل جداً في المشاريع الحقيقه) فتشغيل هذه الكلاسات واحده بعد الاخرى يدوياً متعب جداً. ماذا لو تريد فقط تشغيل ٣٠ كلاس متفرقه منهم في كل مره تعمل تحديث لشفرة مشروعك كإظافة ميزه ما؟ فقرائة اسمائهم والتشغيل اليدوي لهم يعتبر متعب جداً, اذن مالحل؟ الحل هو انشاء Suite يقوم بضم جميع هذه الكلاسات, وحينها تحتاج فقط لتشغيل هذا الـ Suite. انشاء المزيد من كلاسات الاختبارات كلاساتنا السابقه لاتكفي! لذلك سنقوم بكتابة المزيد من الكلاسات حتى نطبق عليهم الـ Suite. والطريقة سهله جداً, فقط نقوم بإنشاء كلاسات جديده بجانب الكلاس الرئيسية (MainTest.java) وكتابة الاختبارات بهم. ماذا سننشئ؟ سننشئ اربعة كلاسات, كل كلاس تقوم بإختبار دالة (الجمع, الطرح, الضرب, القسمة) من الموديل Calculator بشكل اعمق, وهم كالتالي. AdditionTest.class لإختبار والتأكد من عمليات الجمع. SubtractionTest.class لإختبار والتأكد من عمليات الطرح. MultiplicationTest.class لإختبار والتأكد من عمليات الضرب. DivisionTest.class لإختبار والتأكد من عمليات القسمة. ومحتواهم كالتالي: كلاس الـ AdditionTest.class package com.company; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import static org.junit.Assert.assertEquals; public class MathematicalAdditionTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Orange"); } @Test public void addition_a_test(){ // Action int result = calculator.addition(6, 6); // Assert assertEquals(result, 12); // is result actually equal 12? } @Test public void addition_b_test(){ // Action int result = calculator.addition(-1, 8); // Assert assertEquals(result, 7); // is result actually equal 7? } @Test @Category({CategorySlowTest.class}) // Marking this Test as CategorySlowTest, you can add more Categories too. public void addition_c_test(){ // Action int result = calculator.addition(-1, -1); // Assert assertEquals(result, -2); // is result actually equal -2? } } كلاس الـ SubtractionTest.class package com.company; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class MathematicalSubtractionTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Yellow"); } @Test public void subtraction_a_test(){ // Action int result = calculator.subtraction(6, 7); // Assert assertEquals(result, -1); // is result actually equal -1? } @Test public void subtraction_b_test(){ // Action int result = calculator.subtraction(-1, -5); // Assert assertEquals(result, 4); // (-1) - (-5) = 4? } @Test public void subtraction_c_test(){ // Action int result = calculator.subtraction(10, 4); // Assert assertEquals(result, 6); // is result actually equal 6? } } كلاس الـ MultiplicationTest.class package com.company; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import static org.junit.Assert.assertEquals; @Category(CategorySlowTest.class) public class MathematicalMultiplicationTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Brown"); } @Test public void multiplication_a_test(){ // Action int result = calculator.multiplication(6, 6); // Assert assertEquals(result, 36); // is result actually equal 36? } @Test public void multiplication_b_test(){ // Action int result = calculator.multiplication(-1, 5); // Assert assertEquals(result, -5); // is result actually equal -5? } @Test public void multiplication_c_test(){ // Action int result = calculator.multiplication(-4, -4); // Assert assertEquals(result, 16); // is result actually equal 16? } } كلاس الـ DivisionTest.class package com.company; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class MathematicalDivisionTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Purple"); } @Test public void division_a_test(){ // Action int result = calculator.division(12, 6); // Assert assertEquals(result, 2); // is result actually equal 2? } @Test public void division_c_test(){ // Action int result = calculator.division(10, -2); // Assert assertEquals(result, -5); // is result actually equal -5? } } انشاء مشغل (Runner) اجنحة (Suites) والان سننشئ مشغل لكل هذه الكلاسات, والذي من خلال تشغيله يقوم بتشغيل جميع الاختبارات الموجودة بهذه الكلاسات الاربعه جميعاً. ماهو المشغل؟ المشغل عبارة عن كلاس عادية نقوم باستخدام النوتيشن RunWith فوقها, ثم نحدد نوع المشغل المراد بداخل هذه النوتيشن وهو Suite في حالتنا هذه. ثم نحدد لهذا الـ Suite الكلاسات المراد ضمها. كود كلاس مشغل الـ Suite package com.company; import org.junit.runner.RunWith; import org.junit.runners.Suite; // This is the important part, which is annotations this class. @RunWith(Suite.class) @Suite.SuiteClasses({ // List all test classes you want to run them in one time MathematicalAdditionTest.class, MathematicalSubtractionTest.class, MathematicalMultiplicationTest.class, MathematicalDivisionTest.class }) // Empty class public class MathematicalSuiteAllTest { } تعقيب قمنا بجعل هذه الكلاس AllMathematicalTest.java مشغل (Runner) بدلاً من المشغل الافتراضي الذي يأتي مع الـ JUnit. وذلك بتعليمها بالنوتشن RunWith. ثم بتحديد نوع المشغل الذي نريده وهو Suite.class وهكذا اصحبت مشغل اجنحه Suite. ثم نقوم بكتابة جميع الكلاسات المراد تشغيلها بداخل النوتيشن SuiteClasses. ونستطيع انشاء عناصر منها كمشغلات في اكوادنا لاحقاً اذا دعت الحاجة لذلك. تشغيل مشغل الـ Suite اسرع خيار لتشغيله هو من خلال الضغظ على السهم الدائري بجانب اسم الكلاس, كما بالصوره التالي: نتيجة تشغيل مشغل الـ Suite تعقيب قبل كل شئ لاتهتم للنص ذي الون الاحمر! فهو خطئ يحدث فقط في نظام الماك ولا يؤثر بشئ. الان نرى من تشغيل هذا المشغل انه قام بتشغيل جميع الاختبارات بداخل الكلاسات الاربع, كما هو واضح بالصوره السابقه في جهة اليمين, وجميع اختباراتهم قد نجحوا. وهكذا نستطيع اختصار الوقت بأنشاء مشغل لكلاسات عديده او لكلاسات محدده كما تدعو الحاجة في اختبارات مشاريعنا. فمثلاً عند اضافة ميزة جديده في مشروعك خاصة باستخدام الانترنت, فأنت تريد فقط تشغيل الكلاسات التي تحتوي على اختبارات مرتبطه بالانترنت لترى هل مشروعك صامد ام لا. ولكن ماذا لو اردنا ان نشغل فقط بعض من دوال الاختبارات وليس الكلاسات بأكملها؟ هنا يأتي دور الـ Categories كما سيتضح في القسم التالي. استخدام Categories في الـ JUnit نستخدم الـ Categories اذا كانت لدينا دوال اختبار متفرقه سواء بكلاسات عديدة او بنفس الكلاس ونريد تحديدهم ومن ثم تشغيلهم في وقت واحد وبضغطة زر واحده. فبعض الاحيان لانريد تشغيل كل دوال الاختبار في الكلاس بل فقط البعض منهم. فالـ Categories مشابه جداً لعمل الـ Suite, بل هو في الحقيقه مشغل Suite كالسابق ولكنه يمتاز عليه بانه يستطيع قرائة نوتيشن اسمه Category يوضع فوق دوال الاختبار. انشاء فئات (Categories) خاصة بنا حتى تستطيع استخدام هذا النوع من المشغلات, يجب علينا ان ننشئ فئاتنا الخاصه والتي من خلالهم سوف نقوم بتعليم اي دالة اختبار بما يناسبها حسب احتياجاتنا. في هذا المشروع KidCalculator سنقوم بأنشاء فئتين Categories وهم كالتالي: CategoryFastTest.java, وهي عباره عن انترفيس فارغة, سنحتاجها لتوسيم دوال الاختبار السريعه لدينا. CategorySlowTest.java, وهي عباره عن انترفيس فارغة, سنحتاجها لتوسيم دوال الاختبار البطيئه لدينا. كود الـ CategoryFastTest.java package com.company; public interface CategoryFastTest { } كود الـ CategorySlowTest.java package com.company; public interface CategorySlowTest { } انشاء مشغل (Runner) فئات (Categories) الان سوف ننشئ مشغل الفئات (Categories). العملية مشابهه لإنشاء مشغل Suite ولكن الفرق هنا اننا سنقوم بإضافة نوتيشن مسؤول عن الفئات. كود كلاس المشغل package com.company; import org.junit.experimental.categories.Categories; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Categories.class) // This Runner runs only @Tests Methods that annotated with CategorySlowTest.java. @Categories.IncludeCategory(CategorySlowTest.class) // If you want to exclude any Category use: // @Categories.ExcludeCategory(CategorySlowTest.class) @Suite.SuiteClasses({ MainTest.class, // Or we can use our last Suite -> MathematicalSuiteAllTest.class ... // ... that contains all these four classes: MathematicalAdditionTest.class, MathematicalSubtractionTest.class, MathematicalMultiplicationTest.class, MathematicalDivisionTest.class }) public class MathematicalSuiteCategoriesTest { } تعقيب قمنا بجعل هذه الكلاس MathematicalSuiteCategoriesTest مشغل (Runner) بدلاً من المشغل الافتراضي الذي يأتي مع الـ JUnit. وذلك بتعليمها بالنوتشن RunWith. ثم قمنا بتحديد نوع المشغل الذي نريده وهو Categories.class وهكذا اصبح مشغل فئات Categories. ومن ثم اضافة النوتيشن IncludeCategory واعطائه الفئه التي نريد منه ان يشغلها (اعطيناه الانترفيس السابقه التي انشئناها CategorySlowTest.java كفئه). ثم نقوم بكتابة جميع كلاسات الاختبار لدينا بداخل النوتيشن suiteClasses. ونستطيع انشاء عناصر منها كمشغلات في اكوادنا لاحقاً اذا دعت الحاجة لذلك. وضع فئات لدوال الاختبارات والان لنعلم بعض من دوال الاختبارات التي لدينا, بأضافة النوتيشن Category فوقها, ثم الاتيان بالفئه المراده (وهي التي انشئناها CategorySlowTest.java حتى نعلم هذه الدالة بانها بطيئه), كما بالكود التالي: @Test // Marking this Test as CategorySlowTest, you can add more Categories too. @Category({CategorySlowTest.class}) public void addition_c_test(){ // Action int result = calculator.addition(-1, -1); // Assert assertEquals(result, -2); // is result actually equal -2? } تعقيب هذه الدالة موجودة بداخل الكلاس MathematicalAdditionTest.java. نحن قمنا بوضع النوتيشن Category فوقها, وتعليمها بانها دالة بطيئه باستخدام الفئه CategorySlowTest.java التي انشئناها سابقاً بداخل هذا النوتيشن. وضع فئات لكلاس اختبارات بأكملها وكذلك نستطيع وضع فئات على الكلاسات وليس فقط على الدوال, كما بالكود التالي: @Category(CategorySlowTest.class) public class MathematicalMultiplicationTest { تعقيب هذه الكلاس هي MathematicalMultiplicationTest.java. قمنا بوضع النوتيشن Category فوقها, وتعليمها بانها كلاس بطيئه باستخدام الفئه CategorySlowTest.java التي انشئناها سابقاً بداخل هذا النوتيشن. تشغيل مشغل الـ Categories اسرع خيار لتشغيله هو من خلال الضغظ على السهم الدائري بجانب اسم كلاسه, كما بالصوره التالي: نتيجة تشغيل المشغل Category تعقيب نلاحظ ان الدالة addition_c_test التي قمنا بتعليمها بالنوتيشن Category ووضعنا فئتها: CategorySlowTest.java قد تم تشغيلها. وايضاً نلاحظ ان جميع دوال الكلاس MathematicalMultiplicationTest.java قد تم تشغيلهم وذلك بسبب وضع النوتيشن Category وتحديد فئة الكلاس بـ CategorySlowTest.java فوق اسم الكلاس. والفائده من هذا هي اذا كان لدينا اي اختبار بطئ فنستطيع وضعه ضمن فئة الاختبارات البطيئه, ومن ثم التعديل على الشفره البرمجيه لمشروعنا ونعيد تشغيل هذه الاختبارات البطيئه لنرى هل اصبحت سريعه ام لا. في النهاية تعلمنا كيفية استخدام مشغلات الـ Suite و Category وكيفية انشائهم, وهذا يعتبر شئ مهم عندما تريد التحكم في تشغيل اي من الاختبارات.
  21. السلام عليكم ورحمة الله، عدنا لكم من جديد بعد سلسلة بدأنا كتابتها حول تعلم و فهم مكتبة React، اذا كنت جديداً معنا يمكنك العودة للمقال السابق الذي افتتحنا به مجلسنا يتحدث حول مفهوم JSX: درس اليوم هام و جديد كلياً ، قلّما تجد الدورات الأجنبية تركّز عليه و تبسّطه للمتعلمين، لأنه بصراحة يحتاج الى شخص لديه تجربة سابقة بـالجافاسكربت و OOP و ES6، اذا كنت غير دارس لأحد أهمّ هذه المحطات الثلاث فلا أنصحك باكمال قراءة المقال لأنه سيكون مبهماً غير واضح. لنبدأ: أنواع المكونات (Component) الفرق يا أخي العزيز أنه في مكتبة الرياكت يوجد صنفين لكتابة المكونات (Components) - هم غير موجودين بالأساس لكن المبتدأ لازم يفهم - النوع الأول يسمى : مكونات رياكت مبسّطة (Simple React components) مكونات رياكت مركّبة (Complex React components) - في مكونات رياكت البسيطة [1] يمكنك من : ادخال معلومات مباشرة (hardcoded) أو ثابتة (static) على شكل صيغة HTML. استرجاع معلومات حيوية بسيطة مسترجعة من قاعدة بيانات محلية في شكل جيسون (JSON data) يمكنك دمجها في عدة مكونات أخرى و تركيبها في بعضها البعض. - في مكونات رياكت مركّبة [2] : هذه المكونات تكون أكثر تعقيداً مما سبق لأنها ستحوي جميع العمليات المنطقية و الدوال البرمجية المتعلقة بادخال و اخراج و تنظيم المعلومات، لكن في الأخير ستعود بصيغة HTML. حيث يمكنك: استعمال العمليات المنطقية و الدوال البرمجية المتعلقة بادخال و اخراج و تنظيم المعلومات. استعمال الدالة الخاصة بتغير الحالات (State). اضافة أساليب دورة الحياة (lifecycle). اضافة أساليبك الخاصة (custom methods) التي تود تشغيلها حيثما أردت أنت مثلاً، كالضغط على الأيقونة اظهار واجهة ما ..الخ. هذا كل ما تحتاجه لمعرفة المكونات، و الآن أصبحت لديك نظرة شاملة حول مفهومها و دواعي استعمالها. لننتقل الى خطوة أكبر 🙂 صيغة بنية المكوّن (Component Syntax) غريبة هذه الجملة صح! يا عبدالهادي ما هذه الترجمة اللفظية غير واضحة ؛ بنية و صيغة و مكوّن! ايش الفرق يعني .. 😄 - في مكونات رياكت البسيطة و الأصح تدعى بتسميتها الصحيحة بـ المشردة (stateless) : // Simple (stateless) React component const Headline = () => { return <h1>React Cheat Sheet</h1> } في هذه الشفرة المبسطة، كما أخبرتكم أنها تعود بصيغة HTML فقط! لاحظ أنها تعود بجملة ذات عنوان عريض (H1). كما يمكنك ادخال عدة مكونات بسيطة تلو بعضها كـ : // Component must only return ONE element (eg. DIV) const Intro = () => { return <div> <Headline /> <p>Welcome to the React world!</p> </div> } const Intro = () => { return ( <div> <Headline /> <p>Welcome to the React world!</p> </div> ) } const Intro = () => ( <div> <Headline /> <p>Welcome to the React world!</p> </div> ) ماذا تلاحظ في المثال السابق! المثال الأول/الثاني و الثالث مختلف عن بعضه، الفرق أننا استعملنا نهاية الأول و الثاني بقوسين معكوفتين {} و الأخير بقوسين () و كلاهما يؤديان نفس الغرض. فقط الاختلاف أننا نسهل من قراءة الشفرة البرمجية و نكتفي بعدم استعمال دالة العودة (return). - في مكونات رياكت المركبة (المتقدمة) تدعى بــ (ES6 classes) و تسمى أيضاً بـ الذكية. class App extends React.Component { render() { return ( <h1>React Cheat Sheet</h1> ) } } الشفرة السابقة شفرة بسيطة تؤدي نفس غرض المكوّن البسيط (stateless) لكن لا حاجة لنا بهذا، نود استعمال تعليمات منطقية أكبر، و من ضمنها دالة البناء (constructor) و دالة الحالة (State) لنتقدم أكثر و أكثر .. class App extends React.Component { // fires before component is mounted constructor(props) { // makes this refer to this component super(props); // set local state this.state = { date: new Date() }; } render() { return ( <h1> It is {this.state.date.toLocaleTimeString()}. </h1> ) } } تعقدت الشفرة قليلاً، لا عليك كل ما في الأمر أننا استعملنا مكوّن يعطينا الوقت الحالي كل لحظة بالوقت الحقيقي (Real Time). حيث: أضفنا البناء (constructor) معها super() لنجعل كل حدث يشير إلى هذا المكون و يجب حتما استعماله في صيغة ES6. قمنا بتعريف الحالات المتغيرة (local state) و قيمتها المبدئية : دالة التاريخ. أعدنا في دالة العودة (return) بارجاع قيمة التاريخ المتغيرة كل حين بدالة this.state مرفقة باسم المتغير Date و خاصيته toLocaleTimeString() . وصلنا لنهاية موضوع اليوم، في المقال القادم انتظرنا بحول الله سنتعمق في دالة الحالة (State) المتغيرة و دالة (Props) و كيف أنها ستفيدنا في كتابة المشاريع البرمجية و تطبيقات SPA. أتمنى أن تكون المعلومة قد وصلت، كان معكم أخوكم عبدالهادي من الجزائر. (المقال هذا نُقلت أجزائه و شفراته البرمجية بتصرفي من مقال أجنبي سمح لي صاحبه بأخذه جَعله تحت رخصة مجانية).
  22. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذه المقالة سنتعلم كيفية استخدام القواعد (Rules) في الـ JUnit والتي تسمح لنا بأضافة سلوك (behavior) جديد او التغيير في بعض السلوكيات على دوال الاختبارات. المواضيع السابقة (مهمة لفهم هذا المقال) هذه هي المقالات السابقة والتي تعتبر ضروريه لفهم هذا المقال فاذا لم تكن لديك خلفيه مع الـ JUnit انصحك بقرائتها قبل هذا الموضوع والذي يعتبر المقال الرابع من اصل ستة مقالات. رابط المشروع https://github.com/mzdhr/KidCalculator-JUnit وتوجد كلاسات هذه المقالة باسم: RuleTest.java و RuleWatchEye.java في المشروع. واذا اردت الاطلاع على كلاس الـموديل فهذه هي Calculator.java. ماذا سوف تقرئ في هذه المقالة ماهي القواعد Rule و كيفية استخدامها؟ ما الفرق بين النوتيشن ClassRule و Rule وكيفية استخدامهم ومتى؟ امثله لإستخدام بعض من القواعد كقاعدة الـ Timeout و الـ TestName و الـ ErrorCollector. واخيراً كيفية انشاء قاعدة خاصة بنا؟ ماهي القواعد (Rule) للـ JUnit هي عبارة عن عناصر منئشه من كلاس قاعدي (اي كلاس يعمل implements للإنترفيس TestRule يعتبر كلاس قاعدي). فأنت تقوم بأنشائها كـ Field في كلاس الاختبارات. كيفية استخدام هذه القواعد Rules في الـ JUnit بعد انشاء عنصر من كلاس قاعدي كـ Field في كلاس الاختبارات, تضع فوقه النوتيشن Rule او ClassRule وبهذا تصبح هذه القاعدة مطبقه على جميع دوال الاختبارات التي بداخل الكلاس او على الكلاس نفسها. قائمة بجميع القواعد الموجوده في الـ JUnit هذه كلاسات قواعد معده مسبقاً, وجاهزه لإنشاء عناصر منها واستخدامها مع النوتيشن Rule و ClassRule في كلاس اختباراتك. TemporaryFolder لإنشاء ملفات ومجلدات وهميه, لإستخدامهم عند الحاجة اثناء كتابة الاختبارات. ExternalResource مثل سابقتها, ولكن هنا تنشئ عناصر وهميه مثل التعامل مع: socket و server و database connection الخ... ErrorCollector تسمح لدوال الاختبار بالاستمرار للنهاية, حتى مع حدوث خطئ لاتتوقف, وتقوم بجمع كل الاخطاء ومن ثم عرضهم. Verifier اذا اردت ان تتحقق من شئ قبل بداية الاختبارات, مثلاً هل شبكة الانترنت متصلة ام لا. TestWatchman/TestWatcher تسمح لك هذه القاعدة بمراقبة دوال الاختبارات و طباعة Log في الكونسول للمراقبة, مثلاً هل بدء الاختبار؟ هل انتهى؟ هل نجح ام فشل؟. TestName اذا اردت الحصول على اسم دالة الاختبار فهذه القاعدة هي المسؤله عن ذلك, مثلاً تستطيع من خلالها طباعة اسم دالة الاختبار من داخلها. Timeout لوضع حد زمني لدوال الاختبارات, على ان تكتمل كل دالة قبل الوصول لذلك الزمن وإلا تفشل. ExpectedException تسمح لك بالحصول على تحكم اكثر في رسالة ونوع الـ exception المرمي في دالة الاختبار. RuleChain لربط القواعد مع بعضها البعض. قائمة بـ نوتيشنات الخاصه للقواعد (annotation) الموجوده في الـ JUnit Rule تستخدم لتطبيق القاعدة على جميع دوال الاختبارات. ClassRule تستخدم لتطبيق القاعدة على كلاس الاختبارات فقط وليس على دوالها. استخدام النوتيشن ClassRule مع القاعدة Timeout أستخدام النوتيشن ClassRule والذي من خلاله نستطيع تطبيق اي قاعده يأتي فوقها على الكلاس نفسها وليس على دوالها. اما القاعدة Timeout فهي تسمح لتحديد وقت (بأجزاء الثانية) حتى ينتهي الاختبار في مدة هذا الوقت والا يعتبر الاختبار فاشل. المثال // Rule for Class @ClassRule public static TestRule timeout = Timeout.millis(5000); تعقيب بانشاء هذا الـ Field من كلاس القاعدة Timeout وتحديد النوتيشن له بـ ClassRule (لاحظ انه static لانه يعود للكلاس نفسها) فهذا يعني: أن كلاس الاختبارات يجب ان تنهي جميع اختباراتها في اقل من ٥ ثواني, والا تعتبر الاختبارات بها فاشله. اذن متى نستخدم النوتيشن الـ ClassRule؟ اذا اردنا ان نطبق قاعدة على الكلاس نفسها, و ايضاً اذا اردنا من القاعدة ان تعمل لمره واحده فقط. مثلاً عندما تريد الاتصال بالانترنت قبل عمل كلاس الاختبارات هذه ثم اطفاء الانترنت عند نهايتها, او اذا كنت تريد تشغيل السيرفر لتجهيزه قبل عمل كلاس الاختبارات هذه ثم اطفائه عند نهايتها, فـ ClassRule مناسبه جداً. استخدام النوتيشن Rule مع القاعدة Timeout هنا سنستخدم نفس القاعدة Timeout لتحديد فتره زمنيه, ولكن ليس على الكلاس! بل على جميع دوال الاختبارات باستخدام النوتيشن Rule كما بالمثال التالي. المثال // Rules for @Test Methods @Rule public final TestRule timeoutForMethods = Timeout.millis(1005); تعقيب بانشاء هذا الـ Field من كلاس القاعدة Timeout وتحديد النوتيشن له بـ Rule فهذا يعني: أن اي دالة اختبار تأتي بالنوتيشن Test عليها ان تنهي عملها قبل تخطي هذا الوقت وهو تقريباً ثانيه, والا سوف تفشل. اذن متى نستخدم النوتيشن الـ Rule؟ اذا اردنا ان نطبق قاعدة على كل الدوال, بمعنى اخر ان هذه القاعده سوف تعمل بعدد كل دوال الاختبارات المعلمه بالنوتيشن Test في كلاس الاختبارات. فاذا قمت باستخدام هذا النوتيشن لقاعدة تقوم بالاتصال بالانترنت وقطعه, فانك سوف تقوم بتكرار هذه العمليه لكل دالة اختبار. استخدام النوتيشن Rule مع القاعدة TestName مثال اخر لإستخدام النوتيشن Rule مع قاعدة اخرى وهي TestName, وكما جاء سابقاً للـ "TestName: اذا اردت الحصول على اسم دالة الاختبار فهذه القاعدة هي المسؤله عن ذلك, مثلاً تستطيع من خلالها طباعة اسم دالة الاختبار من داخلها." المثال لأنشائها @Rule public final TestName testName = new TestName(); تعقيب عباره عن Field بكلاس الاختبارات. المثال لإستخدامها @Test public void method_name_test(){ System.out.println("This message printed from method -> " + testName.getMethodName()); } الناتج This message printed from method -> method_name_test تعقيب قمنا باستخدام الفيلد testName بداخل دالة الاختبار "method_name_test", لطباعة اسمها. استخدام النوتيشن Rule مع القاعدة ErrorCollector مثال اخر لإستخدام النوتيشن Rule مع قاعدة اخرى وهي ErrorCollector , وكما جاء سابقاً للـ "ErrorCollector: تسمح لدوال الاختبار بالاستمرار للنهاية, حتى مع حدوث خطئ لاتتوقف, وتقوم بجمع كل الاخطاء ومن ثم عرضهم." المثال لإنشائها @Rule public final ErrorCollector errorCollector = new ErrorCollector(); تعقيب عباره عن Field بكلاس الاختبارات. المثال لإستخدامها @Test public void error_collector_test(){ // Action int result01 = calculator.addition(2,2); int result02 = calculator.addition(3,3); int result03 = calculator.addition(4,4); // Assertion errorCollector.checkThat(result01, is(3)); // wrong errorCollector.checkThat(result02, is(3)); // wrong errorCollector.checkThat(result03, is(3)); // wrong } النتيجه تعقيب قمنا باستخدام الفيلد errorCollector مع الدالة checkThat واعطيناه ثلاثة احتمالات خاطئه عمداً, لنرى هل يقوم فقط بالتحقق من الاحتمال الاول ثم يفشل ويوقف الاختبار! كما سنرى كيف يحصل مع الداله assertThat لاحقاً! ام يكمل ويأتينا بالاخطاء كلها (نعم اتى بالاخطاء كلها). الاستخدام بدون القاعدة الـ Error Collector @Test public void no_error_collector_test(){ // Action int result01 = calculator.addition(2,2); int result02 = calculator.addition(3,3); int result03 = calculator.addition(4,4); // Assertion assertThat(result01, is(3)); // wrong assertThat(result02, is(3)); // wrong assertThat(result03, is(3)); // wrong } النتيجه تعقيب بدون استخدام القاعدة ErrorCollector فنحن سنحصل فقط على اول خطئ ثم يتوقف عمل دالة الاختبار. انشاء قاعدة خاصة بنا واستخدام النوتيشن Rule معها ماذا لو ان القواعد المدمجه مع الـ JUnit لم تلبي رغبة كتابة اختباراتك لمشروعك! وتحتاج المزيد او غيرها من القواعد؟ اذن في هذه الحاله تستطيع ان تنشئ قاعدتك الخاصة كما سيأتي. ماهي وظيفة القاعدة التي سوف ننشئها؟ سننشئ قاعدة تقوم بإضافة سلوك اضافي لكل دالة اختبار لدينا. وهذا السلوك هو: ان كل دالة اختبار تقوم بطباعة ثلاثة اشياء: اسمها و اسم كلاسها و كم استغرقت من وقت. خطوات انشاء قاعدة خاصة في الـ JUnit انشاء كلاس اختبارات جديدة في مسار مجلد الاختبارات. عمل implements للـ interface التاليه TestRule. عمل Override للدالة apply. انشاء عنصر جديد من كلاس الـ Statement وجعل الدالة apply تقوم بإرجاعه. وهذا العنصر يحتوي على الدالة evaluate والتي بداخلها سوف نقوم بكتابة الكود الذي سيضيف هذا السلوك الجديد لدوال الاختبارات. الكود (كلاس القاعدة الخاصة بنا) package com.company; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class RuleWatchEye implements TestRule { @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { // ---------- Write Behavior ---------- long start = System.currentTimeMillis(); try { // This code will run when each of @Test Methods runs. base.evaluate(); // Trigger for our @Test Methods code's. System.out.println(); System.out.println("Method ---> " + description.getMethodName()); System.out.println("In Class ---> " + description.getTestClass().getName()); } finally { // This code will run when each of @Test Methods is finish running. System.out.println("Takes ---> " + (System.currentTimeMillis() - start) + " Millisecond"); } // ---------- End of Behavior ---------- } }; } } تعقيب العمل كله يحدث داخل الدالة "evaluate" حيث اننا قمنا بأنشاء العنصر start وجعلناه يخزن وقت البدء. ثم بداخل الـ Try قمنا بكتابة ماذا نريد ان يتم عند تشغيل اي دالة اختبارات. وفي الـ finally قمنا بكتابة ماذا نريد ان يتم عند الانتهاء من تشغيل اي دالة اختبارات. ولاتنسى قرائة التعليقات الموجودة بالكود للإيضاح اكثر, وايضاً قرائة خطوات الانشاء السابقه حتى يسهل الفهم. طريقة الاستخدام // Custom Rule @Rule public final RuleWatchEye ruleWatchEye = new RuleWatchEye(); تعقيب فقط نقوم بعمل عنصر كـ Field منها في كلاس اختباراتنا. ونضع فوقه النوتيشن Rule, وعند تشغيل اي دالة اختبار فسوف يتم تفعيل قاعدتنا عليها. الناتج Method ---> time_out_annotation_test In Class ---> com.company.RuleTest Takes ---> 803 Millisecond تعقيب تم تشغيل الدالة time_out_annotation_test في كلاس الاختبارات RuleTest.java بشكل عادي, وتمت طباعة هذه الاسطر الثالثه السابقه, اذن قاعدتنا تعمل بشكل ممتاز. واذا اردت ان تقوم بطباعة جميع المعلومات للدوال الاخرى فقط قم بتشغيل الكلاس بأكملها. ونستطيع ايضاً استخدام هذه القاعد (وذلك فقط بانشاء عنصر منها كـ Field) في كلاسات اختباراتنا الاخرى. الكود الكامل لكلاس الاختبارات للقواعد في هذه المقالة package com.company; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; import org.junit.rules.TestName; import org.junit.rules.TestRule; import org.junit.rules.Timeout; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; public class RuleTest { // Fields private Calculator calculator; // Rule for Class @ClassRule public static TestRule timeout = Timeout.millis(5000); // Rules for @Test Methods @Rule public final TestRule timeoutForMethods = Timeout.millis(1005); @Rule public final TestName testName = new TestName(); @Rule public final ErrorCollector errorCollector = new ErrorCollector(); // Custom Rule @Rule public final RuleWatchEye ruleWatchEye = new RuleWatchEye(); @Before public void setUp() { // Arrange calculator = new Calculator("Yellow"); } @Test(timeout = 1000) public void time_out_annotation_test() throws InterruptedException { Thread.sleep(800); } @Test public void time_out_global_annotation_test() throws InterruptedException { Thread.sleep(800); } @Test public void error_collector_test(){ // Action int result01 = calculator.addition(2,2); int result02 = calculator.addition(3,3); int result03 = calculator.addition(4,4); // Assertion errorCollector.checkThat(result01, is(3)); // wrong errorCollector.checkThat(result02, is(3)); // wrong errorCollector.checkThat(result03, is(3)); // wrong } @Test public void no_error_collector_test(){ // Action int result01 = calculator.addition(2,2); int result02 = calculator.addition(3,3); int result03 = calculator.addition(4,4); // Assertion assertThat(result01, is(3)); // wrong assertThat(result02, is(3)); // wrong assertThat(result03, is(3)); // wrong } @Test public void method_name_test(){ System.out.println("This message printed from method -> " + testName.getMethodName()); } } في النهاية تعلمنا كيفية استخدام النوتيشن Rule و ClassRule والفرق بينهم. وتطرقنا الى بعض من الامثله للقواعد المدمجة البسيطه (لتسهيل الفهم) مع الـ JUnit كـ ErrorCollector و TestName و Timeout (للإطلاع على المزيد من الامثله لهذه القواعد), وكيفية استخدامهم مع هذه النوتيشنات. وايضاً تعلمنا كيفية انشاء قاعدة خاصة بنا وكيفية استخدامها وتطبيقها في كلاسات اختباراتنا.
  23. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذه المقالة سنتعلم كيفية استخدام الـ JUnitMatchers, لتسهيل كتابة الاختبارات وقرائتها (وخاصة الدالة "assertThat" والتي هي صلب الموضوع). وهو يأتي مع مكتبة الـ JUnit بشكل اساسي, حيث انك لاتحتاج لتثبيت اي ملف jar او اضافة اي اعتمادية لمشروعك. المواضيع السابقة (مهمة لفهم هذا المقال) هذه هي المقالات السابقة والتي تعتبر ضروريه لفهم هذا المقال فاذا لم تكن لديك خلفيه مع الـ JUnit انصحك بقرائتها قبل هذا الموضوع والذي يعتبر المقال الثالث من اصل ستة مقالات. رابط المشروع https://github.com/mzdhr/KidCalculator-JUnit وتوجد كلاس هذه المقالة باسم: MatcherAssertThatTest.java في المشروع. واذا اردت الاطلاع على كلاس الـموديل فهذه هي Calculator.java. ماذا سوف تقرئ في هذه المقالة ماهي انواع الـ Matchers المدعومة في الـ Junit؟ كيفية استخدام الـ JUnitMatchers وبالذات الدالة assertThat؟ كيفية التحقق من كلاس العنصر, وعكس ذلك؟ التحقق من ان العنصر ليس null؟ وايضاً ماهي الطريقة للتحقق من وجود عنصر نصي (string) بداخل عنصر نصي (string) اخر؟ هل هو في البداية ام في النهاية؟ وكيفية التحقق من عناصر الـ boolean؟ واخيراً كيفية التحقق من ان ArrayList تحتوي على عنصر محدد مسبقاً؟ انواع الـ Matchers في الـ JUnit JUnitMatchers والمسمى ايضاً بـ JUnit CoreMatchers وهذا ماسيتم شرحة في هذه المقالة. Hamcrest CoreMatchers لن يتم شرحة, ولكنه مشابه بشكل كبير للسابق, فالاثنين يحتويات على دالة assertThat. وهذا يسبب مشاكل, فاذا قمت بتثبيته ستواجة اختلاط في كتابة الاختبارات, فأنصح كبداية باستخدام النوع الاول اما اذا اردت التعمق فأنصح باستخدام النوع الثاني. ملاحظة: تم بناء النوع الاول وهو JUnitMatchers على النوع الثاني وهو Hamcrest ثم دعمة بشكل رسمي في الـ JUnit. استخدام الـ JUnitMatchers في الـ JUnit في الطريقة التقليدية القديمة تعودنا على كتابة الاختبارات بأستخدام الدالة assertEquals, اما الان فسوف نكتبها بالطريقة الجديدة باستخدام دالة الـ assertThat. مثال: الطريقة القديمة @Test public void assert_old_way(){ // Action int result = calculator.addition(10, 4); // Assert assertEquals(result, 14); } مثال: الطريقة الجديدة @Test public void assert_that_test() { // Action int result = calculator.addition(10, 4); // Assert assertThat(result, is(14)); } تعقيب في الطريقة الجديدة استخدمنا دالة assertThat مع دالة is وهذا يسهل علينا الامر كثيراً. وكأننا نقول هل قيمة الـ result هي 14؟ اذا نعم فالاختبار يعتبر ناجح. وايضاً يمكننا اضافة تعليق لها كما سيأتي. اضافة تعليق للإختبار @Test public void assert_with_message_test(){ // Action int result = calculator.addition(10, 10); // Assert assertThat("This is a message, shows when test failed!", result, is(20)); } تعقيب عند فشل الاختبار فسوف تظهر هذه الرسالة, حيث اننا نستطيع استخدامها لتسهيل علينا تتبع الفشل, كما بالمقال الاول. التحقق من كلاس العنصر @Test public void assert_is_type_x_class_test(){ // Action int result = calculator.addition(10, 5); // Assert assertThat(result, isA(Integer.class)); } تعقيب باستخدام الدالة isA بداخل الدالة assertThat قمنا بالتحقق هل العنصر result هو في الحقيقة من نوع الـ Integer ام لا. وعكس ذلك كما سيأتي لاحقاً. التحقق ان العنصر ليس من كلاس محدده @Test public void assert_not_type_x_class_test(){ // Action int result = calculator.addition(10, 4); // Assert assertThat(result, is(not(instanceOf(Double.class)))); } تعقيب قمنا بالتحقق هل العنصر result ليس من كلاس Double؟ وتم هذا التحقيق باستخدام الدالة is مع دالة النفي not ومن ثم دالة instanceOf التي بدورها تأخد نوع الكلاس المراد التحقق منها. التحقق ان العنصر لايحمل null كقيمة له @Test public void assert_not_null_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, is(notNullValue())); } تعقيب قمنا بالتحقق باستخدام الدالة is والدالة notNullValue, اي كاننا نقول هل العنصر result لا يحمل قيمة null. يوجد عكس هذه الداله وهي nullValue اذا اردت ان تتحقق من ان العنصر يحمل بالفعل قيمة null. التحقق ان عنصر String يحتوي على عنصر String اخر @Test public void assert_contains_string_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, containsString("e")); } تعقيب باستخدام الدالة containsString, قمنا بالتحقق من العنصر color هل يحتوي على حرف الـ e بداخله. طبعاً سينجح الاختبار لإن color يحتوي على قيمة "Red" مسبقاً. التحقق بان العنصر String يحتوي على اي من هذه العناصر الاخرى @Test public void assert_contains_any_with_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, anyOf(containsString("S"), containsString("B"), containsString("d"))); } تعقيب في هذا المثال استخدمنا الدالة anyOf ثم اتينا بسلسه من الدوال containsString للتحقق من اذا كان العنصر color يحتوي على اي منهم. طبعاً سينجح الاختبار لإن اللون color هو عنصر String يحتوي على قيمة "Red" و لإن الاختبار سيرى قيمة "d" بداخله. التحقق ان العنصر String يبدئ بهذه الحروف @Test public void assert_start_with_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, startsWith("R")); // there is also -> endsWith() } تعقيب مشابه للسابقين, ولكن هنا تحققنا ان العنصر color يبدئ بالحرف R باستخدام الدالة startsWith. وايضاً توجد دالة اخرى تقوم بالعكس وهي الدالة endsWith. طبعاً سينجح الاختبار لإن عنصرنا color والذي يحتوي على قيمة "Red" يوجد به حرف "R" في بدايته. التحقق من عنصر boolean هل هو true @Test public void assert_true_test(){ // Action calculator.setOn(); boolean power = calculator.getPower(); // Assert assertThat(power, is(true)); } تعقيب باستخدام كلمة true بداخل الدالة is, قمنا بالتحقق هل ان العنصر power يحمل قيمة true بداخله. والعكس صحيح بالنسبه للتحقق من قيمة الـ false. التحقق من ان ArrayList تحتوي على عنصر محدد @Test public void assert_list_test(){ // Action int number01 = calculator.addition(1, 1); int number02 = calculator.addition(1, 2); int number03 = calculator.addition(1, 3); int number04 = calculator.addition(1, 4); ArrayList<Integer> myList = new ArrayList<>(); myList.add(number01); myList.add(number02); myList.add(number03); myList.add(number04); int itemWanted = 5; // Assert assertThat(myList, hasItem(itemWanted)); } تعقيب قمنا بانشاء اربعة عناصر باستخدام المودل calculator, ثم أضفناهم الى قائمة بأسم myList, وفي النهاية قمنا بانشاء عنصرنا المراد التحقق منه وهو itemWanted. وبأستخدام الدالة hasItem قمنا بهذا التحقق. الكلاس كاملة package com.company; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; public class MatcherAssertThatTest { // Fields private Calculator calculator; @Before public void setUp() { // Arrange calculator = new Calculator("Red"); } @Test public void assert_old_way(){ // Action int result = calculator.addition(10, 4); // Assert assertEquals(result, 14); } @Test public void assert_that_test() { // Action int result = calculator.addition(10, 4); // Assert assertThat(result, is(14)); } @Test public void assert_with_message_test(){ // Action int result = calculator.addition(10, 10); // Assert assertThat("This is a message, shows when test failed!", result, is(20)); } @Test public void assert_is_type_x_class_test(){ // Action int result = calculator.addition(10, 5); // Assert assertThat(result, isA(Integer.class)); } @Test public void assert_not_type_x_class_test(){ // Action int result = calculator.addition(10, 4); // Assert assertThat(result, is(not(instanceOf(Double.class)))); } @Test public void assert_not_null_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, is(notNullValue())); } @Test public void assert_contains_string_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, containsString("e")); } @Test public void assert_contains_any_with_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, anyOf(containsString("S"), containsString("B"), containsString("d"))); } @Test public void assert_start_with_test(){ // Action String color = calculator.getColor(); // Assert assertThat(color, startsWith("R")); // there is also -> endsWith() } @Test public void assert_true_test(){ // Action calculator.setOn(); boolean power = calculator.getPower(); // Assert assertThat(power, is(true)); } @Test public void assert_list_test(){ // Action int number01 = calculator.addition(1, 1); int number02 = calculator.addition(1, 2); int number03 = calculator.addition(1, 3); int number04 = calculator.addition(1, 4); ArrayList<Integer> myList = new ArrayList<>(); myList.add(number01); myList.add(number02); myList.add(number03); myList.add(number04); int itemWanted = 5; // Assert assertThat(myList, hasItem(itemWanted)); } } وكانت هذه اغلب الامثلة والدوال المهمة التي سوف تحتاجها في كتابة اختبارات أسهل بأستخدام دالة الـ assertThat بداخل الـ JUnitMatchers في اجراء الاختبارات مع مكتبة الـ JUnit. وللمزيد من المعلومات حول الـ matchers.
  24. شكرا لك ع الطرح الرائع للتصحيح Xcode 9 وليس 11
  25. السلام عليكم ورحمة الله وبركاته طرحنا مسابقة عالم البرمجة للنقاش الهادف ، و هدفنا إثراء المحتوى العربي في مجال البرمجة ، فاز معنا الطرح المتميز و المفيد حيث قام بتقييم المقالات وترقيتها فريق عالم البرمجة سنذكر بهذه المقالة الفائزين معنا ، و مقالاتهم ، و نشكرهم على ماقدموا من فائدة للجميع ، و إثراء المحتوى العربي في البرمجة. الفائزون في شهر January 2018 المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: المقال الفائز: في الختام: هدفنا في موقع عالم البرمجة إثراء المحتوى العربي في مجال البرمجة ، و تعزيز حب المساعدة بين المبرمجين تستطيع كتابة ماتحب في ساحات النقاش ، و يمكن تكون احد الفائزين معنا بمسابقة عالم البرمجة للنقاش الهادف فهي مازالت مستمره ايضا تستطيع مساعدة المبرمجين بالإجابة عن أسئلتهم ، و حل المشاكل التي تواجههم بقسم سؤال وجواب ؛ لتكون مرجع لبقية المبرمجين شعارنا في عالم البرمجة "إن في قضاء حوائج الناس لذة لا يَعرفها إلا من جربها، فافعل الخير مهما استصغرته فإنك لا تدري أي حسنة تدخلك الجنة." -ابن القيم- وممكن تستفيد من حبيبي القارئ اعلم ان فريق عالم البرمجة يصب كل جهودة لمساعدة المبرمجين الذين يخصصون من وقتهم لنشر العلم المفيد ويساعدون الغير ويارب يقدرنا نوقف معكم ونساعدكم قد مانقدر.
  26. المستوى: مُبتدأ/متوسّط يُمكن الاستفادة من مكتبة Multer في nodejs لرفع الصور والملفّات إلى السيرفر، فبأسطر برمجية بسيطة يُمكن رفع الملفات التي قام المُستخدم بتحديدها let app = require("express")() let multer = require("multer") let upload = multer({ dest: 'uploads/' }).any() app.get("/", (req,res)=>{ res.send("Teting...") }) app.post("/upload", (req, res)=>{ upload(req,res, (err)=>{ if (err) throw err }) res.send(req.files) }) app.listen(3000, ()=>{ console.log("Let's Upload....") }) الكود السابق يقوم باستلام الملفّات التي يُرسلها المستخدم إلى المسار /upload ليقوم برفعها ثم طباعة اسم الملف المُستلم. لكن وبعد تنفيذه قد تتفاجئ بأن عملية الرفع تجري بنجاح، إلا أن الاسم لا يظهر ويتم إرسال مصفوفة فارغة على الرغم من أن عملية الرفع تمّت دون مشاكل. السبب في ذلك هو طبيعة Nodejs، والتي سبق وأن تحدّثت عنها في مقال سابق بعنوان "تنفيذ الطلبات بتسلسل وترتيب في Nodejs باستخدام Async/Await". انصحك بقرائته لفهم آلية عمل إطار العمل بشكل كامل. ما يحدث على أرض الواقع هو أن النظام يبدأ بالرفع، ولأن تنفيذ المهام في nodejs يتم بشكل متوازي لتجنّب تأخير الرد على طلب المستخدم، سيقوم النظام فورًا بطباعة محتويات مصفوفة الملفّات req.files، التي ستكون فارغة بالفعل لأن النظام لم ينتهي بالأصل من عملية الرفع. والحل في هذه الحالة هو استخدام async/await ليُصبح الكود من الشكل: let app = require("express")() let multer = require("multer") let upload = multer({ dest: 'uploads/' }).any() app.get("/", (req,res)=>{ res.send("Testing Routes.....") }) let uploadPromise = (req, res)=>{ return new Promise((Resolve, Reject)=>{ upload(req,res, (err)=>{ if (err) Reject(err) Resolve() }) }) } app.post("/upload", async(req, res)=>{ try{ await uploadPromise(req, res) res.send(req.files) }catch(uploadErr){ throw uploadErr } upload(req,res, (err)=>{ if (err) throw err }) }) app.listen(3000, ()=>{ console.log("Let's Upload....") }) حاول تنفيذ الكود السابق وسترى أن اسم الملف سيظهر دون مشاكل لأن النظام قام أولًا برفع الملف ثم قام بطباعة الاسم، وهذا يعني أن المصفوفة لم تعد فارغة بشكل كامل. الفيديو التالي يشرح الفرق بشكل عملي: أما الراغبين بتحديد لاحقة الملف أو قبول نوع مُحدّد من الملفات فهم بحاجة لتعديل بعض جزئيات الكود، ولتجنّب تعقيد الأفكار ما بين Async/Await، سأقوم باستخدا مثال بسيط عن Multer. let app = require("express")() let multer = require("multer") let upload = multer({dest: "uploads"}) app.post("/", upload.single("photos"), (req,res)=>{ res.send("OK...") }) app.listen(3000, ()=>{ console.log("Ready to upload...") }) الكود السابق يشرح طريقة رفع ملف إلى مُجلّد uploads باستخدام multer، فعند طلب الرابط domain.com/ باستخدام POST فإن النظام سيأخذ الملف الموجود في الحقل photos وسيقوم برفعه. لكن ماذا لو أردنا تغيير الاسم أو اختيار اللاحقة؟ الأمر يتم من خلال ميثود موجودة داخل multer تُعرف بـ diskStorage ليُصبح الكود من الشكل let app = require("express")() let multer = require("multer") let storage = multer.diskStorage({ destination: function(req, file, cb){ cb(null, "uploads") }, filename: function(req, file, cb){ let ext = file.mimetype.split("/") ext = ext[ext.length-1] cb(null, file.originalname + "-"+Date.now()+"."+ext) } }) let upload = multer({storage:storage}) app.get("/", (req, res)=>{ console.log(Date.now()) }) app.post("/", upload.single("photos"), (req,res)=>{ res.send("OK...") }) app.listen(3000, ()=>{ console.log("Ready to upload...") }) قُمنا في الميثود بتعريف خاصيّتين الأولى هي destination الخاصّة بتحديد مكان الرفع، والثانية هي اسم الملف. الشرط الوحيد في الخصائص داخل multer هو استخدام دالة cb، وهي اختصار لـ Call Back لتمرير النتيجة التي نرغب بها. في مثالي في الأعلى قُمت بفحص نوع الملف باستخدام الـ mimeType الخاص به، فلو كان صورة سيظهر بالشكل image/jpeg أو image/png وهكذا. بعدها قمت بإضافة تلك اللاحقة للاسم الذي يُمكنك تسميته كيفما تشاء. أما بخصوص رفع نوع واحد من الملفات دونًا عن الغير فهذا مُمكن عبر تعديل السطر الخاص بتعريف upload ليُصبح من الشكل let upload = multer({storage:storage, fileFilter: function(req, file, cb){ if (file.mimetype != "image/jpeg"){ return cb(null, false) } cb(null, true) }}) قُمنا بإضافة ما يُعرف بالـ fileFilter، وهي خاصيّة موجودة في multer قُمنا فيها بفحص نوع الملف مرّة أُخرى عبر mimeType وفي حالة عدم مُطابقة الشروط نقوم برفض الملف من خلال استخدام إعادة الـ callback فارغ مع false. بهذه الحالة سيقفز النظام عن الملف وسيتجاوزه. الفيديو التالي يشرح كل شيء في حالة وجود أي استفسار يُمكن تركه في التعليقات أو مُراسلتي عبر حسابي في تويتر @FerasAllaou
  27. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله، كيف حال الجميع؟ عساكم بألف خير و عافية. سأحاول باذن الله البدأ في سلسلة جديدة حول تعلم أساسيات رياكت (React) و (RN = React Native) كما تعلمون هي مكتبة عرض (View) أطلقتها شركة الفيسبوك لبناء واجهاتك البرمجية (User Interfaces) بطريقة سلسة و سهلة مبنية على نظام (Virtual DOM). و أول نسخة رسمية منها بتاريخ مارس 2013. و لما نقول أنها مكتبة عرض ليست اطار عمل (MVC) ركّز هنا جيّداً أخي القارئ؛ حيث تمثل هي حرف (V) فقط لا تقدم خدمة المتحكم (Controller) و لا (Model). بداية تعلمك React يصادفك شئ جديد عند كتابة أول مكوّن (Component's) حيث أنها تعود (returning) بصيغة تشبه صيغة HTML! ربما لم تلاحظها في مكتبات أو أطر عمل أخرى. تسمى بالـ JSX فما هي يا ترى JSX ؟ JSX عبارة عن صيغة (syntax) أقول أُخترعت لمكتبة React التي تبدو مشابهة جداً لـ xHTML التي تمكنك من انشاء عناصر واجهتك البرمجية (Create Elements) بسهولة و يسر عن طريقها بدلاً من استعمال وضائف (functions) تستدعيها يدوياً لتنفذ مهمة معيّنة. ربما هذه نقطة مبهمة للبعض لكن ستفهمها بعد قليل باذن الله. من المهم أن تعلم أن جميع مكونات React المبنية بصيغة JSX تترجم من شفرة لشفرة (transpiler) الى تعليمات جافاسكربت حقيقية (Real JavaScript) باستخدام مكتبة تدعى بابل (Babel) تقوم بتحويل الرياكت الى شفرة ES5 القديمة لتشتغل على جميع المتصفحات (حتى القديمة منها). لنكتب مثالا بسيطاً بالـ JSX : return <span> أهلا بعالم البرمجة! </span>; هل لاحظت سهولة كتابة جملة، و ارجاعها للظهور في المصتفح بكل سهولة مرفقة بكلمة (Return). تخيّل لو كتبناها بصيغة ES5 القديمة؟! return React.createElement( 'span', {}, 'أهلا بعالم البرمجة!'); كم سطراً كتبناه لنعيد الجملة للظهور باستخدام جافاسكربت طبيعية! في هذا المثال استعملنا وظيفة (function) تسمى بـ React.createElement صيغتها كالتالي: React.createElement( string|element, [propsObject], [children...]) ماذا لو أردنا كتابة عدة جمل متفرقة بداخل الشفرة البرمجية! ستكون هكذا بلا شك! React.createElement('div', {}, React.createElement('div', {}, 'text1'), React.createElement('div', {}, 'text2', ) ); لكن لسهولة JSX و هذا ما تميّزت به شركة الفيسبوك صراحة في مكتباتها البرمجية، الشفرة السابقة مثلاً باستخدام JSX : function text1() { return <span>text1</span>; } function text2() { return <span>text2</span>; } هنا نستنتج مرة أخرى، أن JSX رائعة جدا و اختزال (shorthand) لكثرة الشفرات البرمجية التي تؤدي نفس الوظيفة. مما يكلفك وقتا اضافيا و كثرة المشاكل (bug's) عند تنقيح برمجياتك و تطبيقاتك؛ هذا كود شامل و أوسع، تلاحظ أنه يمكنك من تقسيم واجهاتك البرمجية عبر مكونات مختلفة و التحكم بها كلٌ على حِدة. من الثلاث خصائص المتوفرة في JSX هي : العناصر المتداخلة (Nested elements): حيث يمكنك الجمع بين عدة عناصر (Multiple elements) في حاوية واحدة (container element) كـ <div> مثل المثال الذي بالأسفل. السمات (Attributes): داخل كل عصنر div لك أن تضيف وظائف متعددة كـ (className، selected، style) ..الخ. تعبيرات الجافاسكربت (JavaScript expressions): يمكنك اضافة تعابير (ليست شرطية statements) داخل JSX كعمليات الحساب و المهم أن تكون ضمن قوسين {} . import React from 'react'; class App extends React.Component { render() { return ( <div> <p>Header</p> <p>Content</p> <p>Footer</p> </div> <div> <h1>{10+1}</h1> </div> <div style={{ height: 10 }}> Hello World! </div> ); } } export default App; في التعبيرات ذكرنا أنه لا يمكن استخدام التعابير الشرطية كـ if و else باستثناء التعبير الشرطي الثلاثي: { i === 1 ? 'true' : 'false' } مثال : import React from 'react'; class App extends React.Component { render() { const i = 1; return ( <div> <h1>{ i === 1 ? 'true' : 'false' }</h1> </div> ); } } export default App; من النصائح التي أقدمها و لا يجب عليك نسيانها: جميع أسماء المكونات (components) تكتب بحروف صغيرة (lowercase) التي تكون مدمجة بـعناصر HTML أو SVG كـ (div, ul, rect, etc.) و لا تنسى اغلاق العناصر بأوسمتها (Close Every Element) مثال مبسط: // DO THIS: return <br/>; return <input type='password' .../>; return <li>text</li>; // NOT THIS: return <br>; return <input type='password' ...>; return <li>text; هذه أهم أساسيات JSX التي يجب على كل شخص معرفتها لمحبي تعلم ReactJS و RN عموماً. أتمنى تكون مفهومة للجميع. و السلام عليكم.
  28. السلام عليكم اخي ممكن برنامج او مثال يشمل هياكل البيانات كامل مش ملاقية اي مثال يشمل المادة باكون ممتنة لك لو عطيتني مثال
  1. عرض المزيد من النشاطات

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل