يرشدك هذا الدليل التعليمي خلال إنشاء اختبار "مرحبًا" لإعدادات Trade Federation (Tradefed أو TF) ويقدّم لك مقدّمة عملية عن إطار عمل TF. بدءًا من بيئة تطوير، يمكنك إنشاء إعداد بسيط وإضافة ميزات.
يقدّم الدليل التعليمي عملية تطوير الاختبار كمجموعة من التمارين، ويتكون كل منها من عدة خطوات توضّح كيفية إنشاء الإعدادات وتحسينها تدريجيًا. يتم توفير جميع نماذج الرموز البرمجية التي تحتاجها لإكمال عملية إعداد الاختبار، ويتم شرح عنوان كل تمرين باستخدام حرف يصف الأدوار المعنيّة بهذه الخطوة:
- د للمطوّر
- I للشركة المُدمِجة
- R لتشغيل الاختبار
بعد إكمال البرنامج التعليمي، ستحصل على إعدادات TF عاملة وستفهم العديد من المفاهيم المهمة في إطار عمل TF.
إعداد اتحاد التجارة
لمعرفة التفاصيل حول إعداد بيئة تطوير TensorFlow، يُرجى الاطّلاع على مقالة إعداد الجهاز. تفترض بقية هذه المقالة التعليمية أنّ لديك بيئة شل مفتوحة تم إعدادها لبيئة TF.
للتبسيط، يوضّح هذا الدليل التعليمي كيفية إضافة إعدادات و فئاتها إلى مكتبة إطار الشفافية والموافقة الأساسية. يمكن توسيع نطاق هذا الإجراء ليشمل تطوير الوحدات خارج شجرة المصدر من خلال تجميع حزمة JAR الخاصة بتنسيق tradefed، ثم تجميع الوحدات باستخدام حزمة JAR هذه.
إنشاء فئة اختبار (د)
لننشئ اختبارًا لعبارة "مرحبًا" يُرسِل رسالة إلى stdout. ينفِّذ اختبار tradefed بشكل عام واجهة IRemoteTest. في ما يلي مثال على تنفيذ HelloWorldTest:
package com.android.tradefed.example; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.invoker.TestInformation; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.result.ITestInvocationListener; import com.android.tradefed.testtype.IRemoteTest; public class HelloWorldTest implements IRemoteTest { @Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World!"); } }
احفظ نموذج التعليمات البرمجية هذا فيملف <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java
وأعِد إنشاء tradefed من وحدة التحكّم:
m -jN
يُرجى العلم أنّ الرمز CLog.i
في المثال أعلاه يُستخدَم لتوجيه الإخراج إلى وحدة التحكّم. يمكنك الاطّلاع على مزيد من
المعلومات حول التسجيل في Trade Federation في مقالة التسجيل (D وI وR).
إذا لم تنجح عملية الإنشاء، يمكنك الرجوع إلى مقالة إعداد الجهاز للتأكّد من عدم تخطّي أي خطوة.
إنشاء عملية ضبط (1)
يمكن تنفيذ اختبارات Trade Federation من خلال إنشاء ملف إعدادات، وهو ملف XML يوجّه Tradefed بشأن الاختبار (أو الاختبارات) التي يجب إجراؤها، بالإضافة إلى الوحدات الأخرى التي يجب تنفيذها وبأي ترتيب.
لننشئ إعدادًا جديدًا لاختبار HelloWorldTest (يُرجى ملاحظة اسم الفئة الكامل لاختبار HelloWorldTest):
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> </configuration>
احفظ هذه البيانات في ملف helloworld.xml
في أي مكان على
نظام الملفات المحلي (مثل /tmp/helloworld.xml
). سيحلّل TF
ملف XML الخاص بالإعدادات (المعروف أيضًا باسم config)، ويحمّل الفئة المحدّدة باستخدام
الاستكشاف، وينشئ مثيلًا لها، ويحوّلها إلى IRemoteTest
، ويُطلِق run
.
تشغيل ملف الإعدادات (R)
من وحدة التحكّم، افتح وحدة تحكّم Tradefed:
tradefed.sh
تأكَّد من أنّ الجهاز متصل بالجهاز المضيف ومن أنّه مرئي لبرنامج tradefed:
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
يمكن تنفيذ الإعدادات باستخدام الأمر run <config>
console. ننصحك بما يلي:
tf> run /tmp/helloworld.xml 05-12 13:19:36 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
من المفترض أن يظهر لك الإخراج "مرحبًا، TF World" على وحدة التحكّم.
يمكنك التأكّد من انتهاء تنفيذ أمر معيّن باستخدام list invocations
أو
l i
في طلب وحدة التحكّم، ومن المفترض ألا يتم طباعة أي شيء. إذا كانت الأوامر تتم تنفيذها حاليًا، يتم عرضها على النحو التالي:
tf >l i Command Id Exec Time Device State 10 0m:00 [876X00GNG] running stub on build(s) 'BuildInfo{bid=0, target=stub, serial=876X00GNG}'
إضافة ملف الإعدادات إلى مسار الفصل الدراسي (D وI وR)
لتسهيل عملية النشر، يمكنك أيضًا تجميع الإعدادات في حِزم JAR الخاصة بـ tradefed. يتعرّف Tradefed تلقائيًا على جميع الإعدادات التي يتم وضعها في مجلدات config على مسار تحميل الحِزم.
على سبيل المثال، انقل ملف helloworld.xml
إلى مكتبة <tree>/tools/tradefederation/core/res/config/example/helloworld.xml
الأساسية لـ tradefed.
أعِد إنشاء tradefed، ثم أعِد تشغيل وحدة تحكّم tradefed، ثم اطلب من tradefed عرض قائمة الإعدادات من classpath:
tf> list configs […] example/helloworld: Runs the hello world test
يمكنك الآن تشغيل ملف الإعدادات helloworld باستخدام:
tf> run example/helloworld 05-12 13:21:21 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
التفاعل مع جهاز (D, R)
حتى الآن، لا يُجري HelloWorldTest أي إجراء مثير للاهتمام. تتخصص منصة Tradefed في إجراء الاختبارات باستخدام أجهزة Android، لذا لنضيف جهاز Android إلى الاختبار.
يمكن للاختبارات الحصول على مرجع لجهاز Android باستخدام TestInformation
، الذي يوفّره الإطار عند استدعاء الأسلوب IRemoteTest#run
.
لنعدِّل رسالة الطباعة HelloWorldTest لعرض الرقم التسلسلي للجهاز:
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); }
الآن عليك إعادة إنشاء tradefed والتحقّق من قائمة الأجهزة:
tradefed.sh
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
دوِّن الرقم التسلسلي المُدرَج على أنّه متاح، وهو الجهاز الذي يجب تخصيصه لخدمة HelloWorld:
tf> run example/helloworld 05-12 13:26:18 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548
من المفترض أن تظهر لك رسالة الطباعة الجديدة التي تعرض الرقم التسلسلي للجهاز.
إرسال نتائج الاختبار (د)
يُبلغ IRemoteTest
عن النتائج من خلال استدعاء طرق في مثيل
ITestInvocationListener
الذي تم تقديمه إلى طريقة #run
. يتحمّل إطار عمل TF نفسه
مسؤولية الإبلاغ عن بدء (من خلال
ITestInvocationListener#invocationStarted)
ونهاية (من خلال
ITestInvocationListener#invocationEnded)
كل عملية استدعاء.
التشغيل التجريبي هو مجموعة منطقية من الاختبارات. للإبلاغ عن نتائج الاختبار،
يكون "IRemoteTest
" مسؤولاً عن الإبلاغ عن بدء إجراء الاختبار،
وبدء كل اختبار وانتهائه، وانتهاء إجراء الاختبار.
في ما يلي الشكل الذي قد يبدو عليه تنفيذ HelloWorldTest مع نتيجة اختبار واحدة تشير إلى تعذُّر الإجراء.
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); TestDescription testId = new TestDescription("com.example.TestClassName", "sampleTest"); listener.testRunStarted("helloworldrun", 1); listener.testStarted(testId); listener.testFailed(testId, "oh noes, test failed"); listener.testEnded(testId, Collections.emptyMap()); listener.testRunEnded(0, Collections.emptyMap()); }
تتضمّن TF العديد من عمليات تنفيذ IRemoteTest
التي يمكنك إعادة استخدامها
بدلاً من كتابة نموذج خاص بك من البداية. على سبيل المثال، يمكن لاختبار InstrumentationTest تنفيذ اختبارات تطبيق Android عن بُعد على جهاز Android وتحليل النتائج وإعادة توجيهها إلى ITestInvocationListener
).
للحصول على التفاصيل، اطّلِع على أنواع الاختبار.
نتائج اختبارات المتجر (1)
إنّ التنفيذ التلقائي لمُستمع الاختبار لإعدادات TF هو TextResultReporter، الذي يُفرِغ نتائج طلب التنفيذ إلى stdout. للتوضيح، يمكنك تنفيذ ملف الإعدادات HelloWorldTest من القسم السابق:
./tradefed.sh
tf> run example/helloworld 04-29 18:25:55 I/TestInvocation: Invocation was started with cmd: /tmp/helloworld.xml 04-29 18:25:55 I/TestInvocation: Starting invocation for 'stub' with '[ BuildInfo{bid=0, target=stub, serial=876X00GNG} on device '876X00GNG'] 04-29 18:25:55 I/HelloWorldTest: Hello, TF World! I have device 876X00GNG 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Running helloworldrun: 1 tests 04-29 18:25:55 W/InvocationToJUnitResultForwarder: Test com.example.TestClassName#sampleTest failed with stack: oh noes, test failed 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Run ended in 0 ms
لتخزين نتائج طلب في مكان آخر، مثل ملف، حدِّد تنفيذًا
ITestInvocationListener
مخصّصًا باستخدام علامة
result_reporter
في الإعدادات.
يتضمّن TF أيضًا مستمع
XmlResultReporter
الذي يكتب نتائج الاختبار في ملف XML بتنسيق مشابه لتنسيق
الذي يستخدمه كاتب XML في JUnit من ant. لتحديد result_reporter في
الإعداد، عدِّل …/res/config/example/helloworld.xml
config:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> </configuration>
الآن، عليك إعادة إنشاء tradefed وإعادة تشغيل نموذج Hello World:
tf> run example/helloworld 05-16 21:07:07 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548 05-16 21:07:07 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_2991649128735283633/device_logcat_6999997036887173857.txt 05-16 21:07:07 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_2991649128735283633/host_log_6307746032218561704.txt 05-16 21:07:07 I/XmlResultReporter: XML test result file generated at /tmp/0/inv_2991649128735283633/test_result_536358148261684076.xml. Total tests 1, Failed 1, Error 0
لاحِظ رسالة السجلّ التي تشير إلى أنّه تم إنشاء ملف XML، ومن المفترض أن يظهر الملف الذي تم إنشاؤه على النحو التالي:
<?xml version='1.0' encoding='UTF-8' ?> <testsuite name="stub" tests="1" failures="1" errors="0" time="9" timestamp="2011-05-17T04:07:07" hostname="localhost"> <properties /> <testcase name="sampleTest" classname="com.example.TestClassName" time="0"> <failure>oh noes, test failed </failure> </testcase> </testsuite>
يمكنك أيضًا كتابة مستمعي الاستدعاء المخصّصين، ما عليهم سوى تنفيذ واجهة ITestInvocationListener.
تتيح أداة Tradefed لعدد متعدّد من مستمعي عمليات الاستدعاء إرسال نتائج الاختبار
إلى وجهات مستقلة متعددة. لإجراء ذلك، ما عليك سوى تحديد علامات
<result_reporter>
متعدّدة في الإعدادات.
مرافق التسجيل (D وI وR)
تشمل مرافق تسجيل TF إمكانية إجراء ما يلي:
- تسجيل السجلات من الجهاز (المعروف أيضًا باسم logcat للجهاز)
- تسجيل السجلات من إطار عمل Trade Federation الذي يعمل على الجهاز المضيف (المعروف أيضًا باسم سجلّ المضيف)
يسجِّل إطار عمل TF تلقائيًا logcat من الجهاز المخصّص ويُرسِله إلى مستمع الاستدعاء لمعالجته.
XmlResultReporter
بعد ذلك، يتم حفظ سجلّ الجهاز الذي تم تسجيله كملف.
يتم تسجيل سجلات مضيف TF باستخدام
CLog wrapper
لفئة Log في ddmlib. لنبدِّل العبارة
System.out.println
السابقة في HelloWorldTest إلى العبارة
CLog
:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device %s", getDevice().getSerialNumber());
يعالج CLog
إدراج السلاسل مباشرةً، على غرار
String.format
. عند إعادة إنشاء TF وإعادة تشغيله، من المفترض أن تظهر رسالة log في stdout:
tf> run example/helloworld … 05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548 …
بشكلٍ تلقائي، يُخرج tradefed
رسائل سجلّ المضيف
إلى stdout. يتضمّن TF أيضًا عملية تنفيذ سجلّ تُسجِّل
الرسائل في ملف:
FileLogger.
لإضافة تسجيل الملفات، أضِف علامة logger
إلى الإعدادات، مع تحديد اسم الصف الكاملFileLogger
:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> <logger class="com.android.tradefed.log.FileLogger" /> </configuration>
الآن، أعِد إنشاء مثال helloworld وشغِّله مرة أخرى:
tf >run example/helloworld … 05-16 21:38:21 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_6390011618174565918/device_logcat_1302097394309452308.txt 05-16 21:38:21 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt …
تشير رسالة السجلّ إلى مسار سجلّ المضيف الذي يجب أن يحتوي عند عرضه على رسالة سجلّ HelloWorldTest:
more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
مثال على الإخراج:
… 05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
خيارات المعالجة (D وI وR)
يمكن أيضًا للكائنات المحمَّلة من إعدادات TF (المعروفة أيضًا باسم كائنات الإعدادات)
تلقّي بيانات من مَعلمات سطر الأوامر من خلال استخدام التعليق التوضيحي
@Option
.
للمشاركة، تطبِّق فئة عناصر الإعدادات التعليق التوضيحي @Option
على حقل عضو وتزوّده باسم فريد. يتيح ذلك تعبئة قيمة حقل
العضو من خلال خيار سطر الأوامر (ويؤدي أيضًا إلى
إضافة هذا الخيار تلقائيًا إلى نظام مساعدة الإعداد).
ملاحظة: لا تتوفّر بعض أنواع الحقول. للحصول على وصف للأنواع المتوافقة، اطّلِع على OptionSetter.
لنضيف @Option
إلى HelloWorldTest:
@Option(name="my_option", shortName='m', description="this is the option's help text", // always display this option in the default help text importance=Importance.ALWAYS) private String mMyOption = "thisisthedefault";
بعد ذلك، لنضيف رسالة سجلّ لعرض قيمة الخيار في HelloWorldTest لنتمكّن من إثبات أنّه تم استلامه بشكل صحيح:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { … CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);
أخيرًا، أعِد إنشاء TF وشغِّل helloworld. من المفترض أن تظهر لك رسالة سجلّ تتضمّن القيمة التلقائية
my_option
:
tf> run example/helloworld … 05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'
تمرير القيم من سطر الأوامر
أدخِل قيمة لسمة my_option
، ومن المفترض أن تظهر لك سمة
my_option
مملوءة بهذه القيمة:
tf> run example/helloworld --my_option foo … 05-24 18:33:44 I/HelloWorldTest: I received option 'foo'
تتضمّن إعدادات TF أيضًا نظام مساعدة يعرض تلقائيًا
نص المساعدة لحقول @Option
. جرِّب ذلك الآن، ومن المفترض أن يظهر أمامك
نص المساعدة الخاص بـ my_option
:
tf> run example/helloworld --help Printing help for only the important options. To see help for all options, use the --help-all flag cmd_options options: --[no-]help display the help text for the most important/critical options. Default: false. --[no-]help-all display the full help text for all options. Default: false. --[no-]loop keep running continuously. Default: false. test options: -m, --my_option this is the option's help text Default: thisisthedefault. 'file' logger options: --log-level-display the minimum log level to display on stdout. Must be one of verbose, debug, info, warn, error, assert. Default: error.
لاحِظ الرسالة حول "طباعة الخيارات المهمة فقط". للحدّ من
الارتباك في مساعدة الخيارات، يستخدم TF السمة Option#importance
لتحديد
ما إذا كان سيتم عرض نص مساعدة حقل @Option
معيّن عند تحديد
--help
. تعرِض --help-all
دائمًا مساعدة بشأن
جميع حقول @Option
، بغض النظر عن أهميتها. لمعرفة التفاصيل، يُرجى الاطّلاع على
Option.Importance.
تمرير القيم من أحد الإعدادات
يمكنك أيضًا تحديد قيمة الخيار ضمن الإعداد عن طريق إضافة عنصر
<option name="" value="">
. يمكنك اختبارها باستخدام
helloworld.xml
:
<test class="com.android.tradefed.example.HelloWorldTest" > <option name="my_option" value="fromxml" /> </test>
من المفترض أن تؤدي إعادة إنشاء helloworld وتشغيله إلى عرض هذا الإخراج:
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
من المفترض أن يتم أيضًا تعديل مساعدة الضبط للإشارة إلى القيمة التلقائية لسمة
my_option
:
tf> run example/helloworld --help test options: -m, --my_option this is the option's help text Default: fromxml.
تقبل أيضًا عناصر الضبط الأخرى المضمّنة في ملف الإعدادات helloworld، مثل
FileLogger
، الخيارات. الخيار
--log-level-display
مثير للاهتمام لأنّه لفلترة السجلات التي
تظهر على stdout. في وقت سابق من البرنامج التعليمي، ربما لاحظت الرسالة "مرحبًا،
عالم TF! لقد توقفت رسالة السجلّ "لديّ جهاز …" عن الظهور على stdout بعد أن
بدّلنا استخدام FileLogger
. يمكنك زيادة مستوى التفصيل في تسجيل الرسائل إلى stdout من خلال إدخال الوسيطة --log-level-display
.
جرِّب ذلك الآن، ومن المفترض أن تظهر رسالة السجلّ "لديّ جهاز" مجددًا على stdout، بالإضافة إلى تسجيلها في ملف:
tf> run example/helloworld --log-level-display info … 05-24 18:53:50 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
لا يوجد المزيد.
نذكّرك بأنّه إذا واجهت مشكلة، يتضمّن رمز مصدر Federation الكثير من المعلومات المفيدة التي لا تظهر في المستندات. إذا لم تنجح أي من الطرق الأخرى، يمكنك طرح السؤال في مجموعة Google الخاصة بمنصّة android ، مع تضمين "اتحاد التجارة" في موضوع الرسالة.