في عالم واجهات الإنسان والآلة (HMI)، يمثل دمج تقنيات متنوعة لتجارب مستخدم سلسة تحديات فريدة. دعونا نستعرض تصميم واختبار التطبيقات متعددة التقنيات ذات الوظائف المنفصلة الحرجة للسلامة وغير الحرجة. من خلال الاستفادة من أدوات متخصصة مثل Squish for Qt و AltTester SDK لـ Unity، نقدم نهجاً شاملاً لتوحيد أتمتة الاختبار، بما يضمن تطويراً فعّالاً وضمان جودة قوياً. اكتشف كيف يمكن لهذه المنهجيات تبسيط مشاريع HMI الخاصة بك، وتقليل النفقات العامة، وتعزيز جودة البرمجيات بشكل عام.

مقدمة إلى واجهات HMI في السيارات وفصل الواجهات

يتضمن تصميم واجهة الإنسان والآلة (HMI) إنشاء واجهات مستخدم تتيح للمستخدمين التفاعل بفعالية مع الآلات. في في سياق صناعة السيارات، تُعد واجهات HMI حلولاً معقدة بشكل خاص لأن المستخدمين يتفاعلون مع السيارة على مستويات متعددة: القيادة، واستخدام خدمات الترفيه، وضبط التدفئة، وغير ذلك.

يحمل كل مستوى خدمة أهمية متفاوتة؛ على سبيل المثال، الفشل في الاستجابة لأمر صوتي لخفض النافذة أمر غير مهم نسبيًا، لكن عدم عرض تحذير ABS يمكن أن يكون خطيرًا. لذلك، تميز معايير صناعة السيارات بين أنواع مختلفة من التطبيقات والخدمات. يتم فصل التطبيقات المتعلقة بالسلامة عن التطبيقات غير المتعلقة بالسلامة، وتُرسل الإشارات الخاصة بالوظائف الحرجة، مثل الفرامل، عبر أسلاك مختلفة عن تلك الخاصة بالوظائف غير الحرجة، مثل الملاحة.

في مثل هذه الحالات، يجب على فريق الهندسة تطوير تطبيقات منفصلة لواجهة الإنسان والآلة (HMI) وأحياناً اختيار تقنيات مختلفة لتحقيق هذا الهدف. وفي النهاية، يُعرض كلا التطبيقين فوق بعضهما البعض لتقديم تجربة مستخدم كاملة.

من منظور التطوير، يُعتبر هذا الأسلوب فعّالًا – إذ يحتاج النظام فقط إلى تشغيل تطبيقين اثنين. ويضمن مصممو واجهة المستخدم والمطوّرون تكاملًا جماليًا مُرضيًا لهذين التطبيقين. علاوة على ذلك، يتمتع هذا النهج بمزايا إضافية: إذ يمكن تطوير التطبيقات التي تستخدم تقنيات متنوعة بواسطة فرق مستقلة، مما يتجنب التداخل التشغيلي بينها.

التحديات في اختبار تطبيقات HMI متعددة التقنيات

دعونا الآن نفحص عملية الاختبار لمثل هذه التطبيقات بمزيد من التفصيل. ستُدار كل منها بواسطة فرق اختبار منفصلة مكلفة بتطوير أتمتة مستقلة لهذه التطبيقات. علاوة على ذلك، ستُجرى نتائج الاختبار وضمان الجودة بشكل منفصل لكل منها. مصطلح "منفصل" بالغ الأهمية هنا؛ فبينما يسهّل مرحلة التطوير، إلا أنه يثبت أنه أقل فائدة أثناء الاختبارات. يُدخل هذا الفصل جهوداً وتكاليف إضافية ويترك مسألة سلوك النظام الإجمالي دون حل.

دمج تطبيقات Qt6 وUnity في أتمتة الاختبارات

لدينا تطبيق قائم على Qt6 يعرض محتوى ثابتاً، مثل الأيقونات أو رسائل التحذير أو القوائم. وفي الطبقة الثانية، لدينا تطبيق قائم على Unity. يعرض رسوماً متحركة للسرعة وعدد الدورات في الدقيقة، وخرائط متحركة، والمزيد، باستخدام نهج المشهد ثلاثي الأبعاد.

تتمثل المهمة في إنشاء أتمتة اختبار لمثل هذا الإعداد. ويتم تسليم التطبيقات ضمن محاكٍ افتراضي – يمكن أن يكون QEMU أو صورة Docker. ومن المتطلبات الأساسية دمج أتمتة الاختبار في إطار اختبار واحد وإنشاء حالات اختبار لاختبار كلا التطبيقين دفعة واحدة.

Architecture diagram showing communication between Qt6 and Unity applications in test automation.
إعداد بيئة الاختبار

اختيار الأدوات المناسبة: Squish for Qt وAltTester SDK for Unity

عندما يتعلق الأمر بـ Qt، فإن النهج المعقول الوحيد هو استخدام الأدوات من مجموعة Qt لاختبار التطبيق. فهي مصممة لدعم تقنيتها الخاصة بشكل كامل. إطار الاختبار الرسمي المصمم لـ Qt هو Squish. هذا الحل هو خيارنا الأول (والوحيد)، حيث يوفر دعمًا شاملاً وتجربة أتمتة اختبار سلسة وجاهزة للاستخدام.

يتضمن اختيار إطار الاختبار لتطبيق Unity بعض القيود التي يجب تلبيتها:

  • إمكانية الربط مع Squish،
  • سعر معقول،
  • الاستخدام في الوضع بلا واجهة (لأغراض التكامل المستمر CI).

كانت إحدى الأدوات التي تم تقييمها بشكل أولي هي AltTester SDK – إطار عمل مفتوح المصدر تديره شركة Alttom. توفر Alttom نسخة تجارية من AltTester مع دعم كامل وإمكانيات معززة.

بالنسبة لاحتياجاتنا، كان AltTester SDK كافياً لبدء التنفيذ الأولي وغطى جميع متطلباتنا.

تصميم بنية موحدة لإطار الاختبار

بعد تقييم الأدوات، قررنا أن يكون Squish أساسًا لجميع أنشطة الاختبار، مثل تشغيل الاختبارات أو إعداد التقارير.

وذلك لأن AltTester SDK ليس إطار عمل اختبار كامل الوظائف، بل هو برنامج تشغيل (driver) يتيح الاتصال بتطبيق Unity مُجهّز بأدوات القياس وفحص عناصره. ولا يتضمن خيارات إعداد التقارير (باستثناء طريقة لقطة الشاشة)، ولتشغيل الاختبارات المكتوبة له، سنحتاج إلى تشغيل نصوص Python أو C# أو JAVA أو استخدام إطار عمل اختبار يوفر جميع الوظائف المتعلقة بالاختبار (مثل نهج BDD أو إعداد التقارير).

أدناه، يمكنك الاطلاع على البنية النهائية التي قررنا تنفيذها.

يتم تجهيز تطبيق Unity أثناء عملية البناء بإضافة AltTester SDK الخاصة بـ Unity، ومشغّل اختبارات Squish، وأغلفة Python، وأدوات مساعدة كُتبت لتوفير الوظائف المطلوبة، وملفات تحتوي على خرائط الكائنات لكلا التطبيقين.

Project structure for integrating Qt6 and Unity in an automated testing environment.
البنية العامة لإطار الاختبار

يقوم المشغّل بتنفيذ الاختبارات من خلال الاتصال بتطبيقات Qt (اتصال أصلي) وUnity (عبر AltDriver SDK). ينفذ الخطوات المكتوبة وفق منهج BDD، ويجمع السجلات ولقطات الشاشة ومنتجات الاختبار الأخرى، وأخيراً يجمع كل شيء في تقرير اختبار.

جعل تطبيقات HMI قابلة للاختبار باستخدام Squish وAltTester SDK

يجب أن يتصل إطار الاختبار بالتطبيقات الخاضعة للاختبار لتحقيق النتائج.

يمكن تنفيذ أدوات Squish بطريقتين:

  • الارتباط بالتطبيق عند بدء تشغيله،
  • تضمين خطاف Squish في التطبيق أثناء بنائه.

قررنا استخدام الخيار الأول، حيث سمح لنا إعداد بيئة الاختبار بذلك.

يجب إضافة AltTester SDK خلال مرحلة بناء تطبيق Unity. فمن المستحيل إجراء الأجهزة على تطبيق مبني بالفعل، وهو ما يفرض بعض الصعوبات. والأهم من ذلك، إذا أردنا استخدام AltTester SDK، فيجب أن يكون لدينا إمكانية الوصول إلى عملية بناء تطبيق Unity وتعديلها لتوفير الأجهزة.

طريقة تجهيز تطبيق Unity واضحة تمامًا: يحتاج المستخدم إلى بناء إضافة AltTester SDK، وإضافة بعض التبعيات إلى مشروع Unity، واستيراد الإضافة إليه (وثائق حول استيراد حزمة AltTester في Unity Editor).

بالطبع، قد تكون هناك حاجة إلى بعض التعديلات والضبط الإضافية، اعتماداً على مواصفات المشروع. احتجنا إلى تعديل نص البناء لمشروع Unity لجعل الأمور تعمل. إليك مثال على أدوات سطر الأوامر:

# الخطوة 1: إعداد مشروع Unity مع التبعيات. python3 update_for_altester.py # الخطوة 2: استيراد إضافة AltTester Unity. ./Unity -quit -batchmode -nographics -disableaudio -importPackage AltTester-1.8.2.unitypackage -projectPath . # الخطوة 3: بناء المشروع باستخدام طريقة بناء مخصصة. ./Unity -quit -batchmode -nographics -disableaudio -projectPath . -executeMethod SpyroBuilder.BuildAltTester

تنفيذ إطار الاختبار: خرائط الكائنات والمزيد

في هذه المرحلة، كان لدينا تطبيقا Squish وUnity متصلين بإطار الاختبار الخاص بنا. كان بإمكان الاختبارات فحص الكائنات في كلا التطبيقين، والتحقق من خصائصها، والتفاعل معها، وتنفيذ جميع أنشطة الاختبار التي صممناها.

خرائط الكائنات

أنشأنا خرائط كائنات لكلا التطبيقين للوصول السريع والبسيط إلى الكائنات.
يمكن إنشاء خريطة كائنات Squish تلقائيًا باستخدام Squish IDE وأدوات الفحص. الكائنات هي أسماء رمزية، وتُحدَّد قيمها بقائمة من المعاملات، مثل «العنوان»، و«النوع»، وما إلى ذلك. هذا مثال على خريطة كائنات Squish:

# العرض الرئيسي لمشغل الوسائط media_player_screen_main_view = { "title": "MediaPlayer", "type": "QQuickWindowQmlImpl", "visible": True } # كائنات قائمة تشغيل مشغل الوسائط media_player_playlist_view = { "container": media_player_screen_main_view, "type": "ListsScreen", "visible": True } media_player_playlist_text = { "container": media_player_playlist_view, "text": "قائمة التشغيل", "type": "Text", "visible": True }

بعد تعريف الكائن، يستطيع Squish الوصول إليه، أو التحقق من خصائصه، أو التفاعل معه. إليك مثالاً على طريقة التغليف للعثور على الكائنات في Squish:

def find_object(obj, timeout=1000, visible_object=True): """يبحث عن كائن ويعيده. لا يسجل أي بيانات. Args: object_name (str or object): اسم الكائن المراد العثور عليه timeout (int): مهلة البحث بالمللي ثانية. القيمة الافتراضية 1000. visible_object (bool): هل الكائن مرئي؟ يحدد دالة Squish المستخدمة. Returns: obj: الكائن الذي تم العثور عليه، أو None إذا لم يتم العثور عليه. """ try: if isinstance(obj, str): if visible_object: obj = squish.waitForObject(getattr(names, obj), timeout) else: obj = squish.findObject(getattr(names, obj)) except LookupError as ex: return None except Exception as ex: raise Exception(ex) return obj

وداخل بيئة تطوير Squish…

Squish IDE object map showing UI element names used in Qt6 and Unity test automation.
بيئة تطوير Squish IDE مع العنصر المحدد وخصائصه

تُعد خرائط كائنات Unity مع AltTester SDK أكثر تعقيدًا بعض الشيء. يمكن إنشاؤها باستخدام Unity Editor (الطريقة الأسهل) أو باستخدام AltTester SDK Driver والفحص اليدوي من سطر الأوامر.

تتيح AltTester SDK التعرف على الكائنات بطرق مثل الاسم والمسار والنص والمعرّف وغيرها. ويمكن استخدامها اعتمادًا على إعداد المشهد أو شجرة الكائنات، وتوفر مرونة لتنفيذ وظائف للعثور على الكائنات. فيما يلي مثال على خريطة الكائنات الخاصة بنا لتطبيق Unity.

charging_toggle = {"by_selector": "NAME", "search_value": "Charging_Toggle"} navigation_toggle = {"by_selector": "NAME", "search_value": "Navigation_Toggle"} vehicle_toggle = {"by_selector": "NAME", "search_value": "Vehicle_Toggle"} engine_economy_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (1)"} engine_economy_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (1)[1]"} engine_balanced_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (2)"} engine_balanced_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (2)[1]"} engine_performance_button = {"by_selector": "NAME", "search_value": "CarToggleForGroup (3)"} engine_performance_label = {"by_selector": "PATH", "search_value": "//CarToggleForGroup (3)[1]"}

قد تبدو دالة الحصول على الكائنات من المشهد على النحو التالي:

def get_object(object_name, is_enabled=True, timeout=0): """Finds and returns an object. Does not log. Args: object_name (str): Name of the object to be found. is_enabled (bool): is object active (true by default) Raises: Exception: When exceptions other than 'object not found' are encountered Returns: obj: Found object, or None if not found. """ try: obj_data = getattr(names, object_name) if timeout > 0: return driver.wait_for_object( getattr(alttester.By, obj_data["by_selector"]), obj_data["search_value"], enabled=is_enabled, timeout=timeout, interval=0.2, ) else: return driver.find_object( getattr(alttester.By, obj_data["by_selector"]), obj_data["search_value"], enabled=is_enabled, ) except (alttester.NotFoundException, alttester.WaitTimeOutException) as ex: return None except Exception as ex: logger.info(f"Exception while looking for object: |{object_name}|") raise Exception(ex)

في سطر أوامر Python، يبدو البحث عن الكائنات هكذا:

AltTester output in Python console showing a found UI object in Qt6 and Unity test automation.

في تطبيق Unity، هذا كائن نموذجي:

Vehicle HMI screen showing charging status tested in Qt6 and Unity integration.
تطبيق Unity مع كائن محدد

كما ذُكر سابقًا، يتيح AltTester SDK العثور على الكائنات باستخدام عدة طرق. في هذا المثال، تم استخدام طريقة By.NAME، لكن يمكن للمستخدم الاختيار بين PATH وTEXT وID وغيرها (وثائق حول العثور على الكائنات).

عند العثور على كائن، يتيح كل من Squish وAltTester SDK للمستخدم فحص خصائصه، والحصول على نص الكائن، والنقر عليه، أو القيام بأي إجراء آخر مطلوب لإنشاء خطوة اختبار.

قدرات API الخاصة بـ Squish وAltTester SDK

يكشف AltTester SDK عن واجهة برمجة التطبيقات للعثور على الكائنات والتفاعل معها وفحص خصائصها. تتيح بعض الميزات المفيدة للمستخدمين التعمق أكثر في تطبيق Unity، مثل استدعاء طرق مكونات Unity أو التفاعل مع خصائص المكونات. كما تتوفر الوظائف المرتبطة بالمشاهد، ويمكن استخدامها لتحميل المشهد المطلوب أو إلغاء تحميله، أو التحقق من أن المشهد الحالي صحيح. هناك طريقة أخرى وهي التقاط لقطة شاشة. تقوم الوظيفة بالتقاط لقطة شاشة وحفظها كملف PNG، والذي يمكن لاحقًا إرفاقه بتقارير الاختبار.

توفر واجهة Squish API، باستثناء الطرق المتعلقة بالاختبار، الوظائف اللازمة لتنظيم سير الاختبار. على سبيل المثال، يمكن للمستخدم أخذ طريقة test.fail() وتغليفها وإضافة أمور أخرى يحتاجها إعداد الاختبار. في حالتنا، قمنا بتغليف test.fail() لتوفير وظائف إضافية مع خطوة الاختبار الفاشل عند اختبار تطبيق Unity، وأضفنا خطوة لقطة شاشة AltTester SDK:

def screenshot(): """Takes screenshot Args: none Returns: none """ dt = datetime.now() timestamp = dt.strftime("%Y%m%d_%H%M%S") path = Path(f'{os.getcwd()}/screenshots') if not os.path.exists(path): os.makedirs(path) scr_path = Path(f'{path}/screenshot_{timestamp}.png') try: driver.get_png_screenshot(path=scr_path) test.attachFile(str(scr_path), "Alttester screenshot") except: test.xfail("There was a problem while taking the screenshot") def test_fail(fail_message): screenshot() test.fail(fail_message)

معالجة التفاعلات

توفر كلتا الأداتين إمكانات التفاعل.

في Squish، هناك عدة طرق، مثل النقر أو الضغط أو حتى فئة Gesture Builder، التي تتيح إنشاء إيماءات بسيطة ومعقدة.

يتبع AltTester SDK نهجًا مشابهًا، بدءًا من طرق الضغط أو التحريك البسيطة وصولًا إلى التفاعلات متعددة النقاط المعقدة. يمكنه إنشاء اللمس (BeginTouch()، MoveTouch()، EndTouch()). لذا، في كلتا الحالتين، يمكن للمستخدمين محاكاة التفاعلات والإيماءات بسهولة ومرونة.

أثر أتمتة الاختبارات المتكاملة على جودة البرمجيات

أتاح لنا استخدام AltTester SDK وSquish معًا إنشاء سيناريوهات اختبار قادرة على اختبار تطبيقين مطوّرين بتقنيتين مختلفتين. ويمكن للسيناريوهات التبديل بين السياقات بسلاسة وتنفيذ خطوات الاختبار. وتوفر تقارير الاختبار جميع المعلومات اللازمة في مكان واحد، دون الحاجة إلى إنشاء خطوط أنابيب منفصلة في CI لتشغيل جميع عمليات الأتمتة.

هل تبحث عن متخصصين في واجهات الآلة البشرية (HMI)؟

تعرّف على كيفية دعمنا لمنتجك القادم – اطّلع على عرض واجهة الإنسان والآلة، ولا تتردد في التواصل معنا في حال وجود أي أسئلة.

الأسئلة الشائعة

يتيح دمج Qt6 وUnity للمطورين الجمع بين واجهات المستخدم المبنية في Qt والبيئات ثلاثية الأبعاد المنشأة في Unity. وهذا يمكّن من إنشاء تطبيقات أكثر تقدماً، لا سيما في سيناريوهات المحاكاة أو واجهة الإنسان والآلة (HMI) أو التصور المرئي.

يتيح استخدام Qt6 وUnity في أتمتة الاختبارات للفرق التحقق من منطق واجهة المستخدم والتفاعلات ثلاثية الأبعاد ضمن سير عمل واحد. يساعد ذلك في ضمان عمل التواصل بين المكونات بشكل صحيح عبر التطبيق بأكمله.

عادةً ما تتواصل تطبيقات Qt6 وUnity من خلال واجهات محددة مثل المقابس (sockets) أو واجهات برمجة التطبيقات (APIs) أو آليات المراسلة. وهذا يسمح لها بتبادل البيانات ومزامنة السلوك أثناء التشغيل والاختبار.

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

يُعد هذا النهج مفيدًا بشكل خاص في المشاريع التي تتضمن المحاكاة، أو أنظمة HMI، أو التطبيقات التي تحتاج فيها بيئة ثلاثية الأبعاد إلى التحكم أو التوسيع عبر واجهة مبنية على Qt.