مثال على اختبار TF الشامل

يرشدك هذا الدليل التوجيهي خلال عملية إنشاء "hello world" اتحاد تجاري إعداد الاختبار (الفريق التقليدي أو TF) ويمنحك مقدمة عملية عن فريق العمل (TF) إطار العمل. بدءًا من بيئة تطوير، ستقوم بإنشاء تصميم على تهيئة الميزات وإضافتها.

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

  • D للمطوّرين
  • I لشركة التكامل
  • R لأداة تشغيل الاختبار

بعد إكمال الدليل التوجيهي، ستكون لديك إعدادات TF صالحة وفهم العديد من المفاهيم المهمة في إطار عمل TF.

إعداد اتحاد تجاري

للحصول على تفاصيل حول إعداد بيئة تطوير TF، يمكنك الاطّلاع على الجهاز الإعداد: يفترض الجزء المتبقي من هذا البرنامج التعليمي أن لديك واجهة أوامر مفتوحة على بيئة TF.

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

إنشاء صف اختبار (D)

لننشئ اختبار hello world الذي يفرغ فقط رسالة إلى stdout. حاسمة يقوم الاختبار المقايضة بشكل عام IRemoteTest من واجهة pyplot. في ما يلي طريقة تنفيذ اختبار 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 وإعادة إنشاء المقايضة من واجهة المستخدم:

m -jN

يُرجى العِلم أنّه يتم استخدام CLog.i في المثال أعلاه لتوجيه المخرجات إلى وحدة التحكّم. المزيد يمكنك الاطّلاع على معلومات حول تسجيل الدخول إلى الاتحاد التجاري في المقالة تسجيل (D، I، R).

إذا لم تنجح عملية الإنشاء، يُرجى الرجوع إلى الجهاز يمكنك إجراء عملية الإعداد لضمان عدم تفويت أي خطوة.

إنشاء تهيئة (I)

تصبح اختبارات الاتحاد التجاري قابلة للتنفيذ من خلال إنشاء التهيئة، وهي عبارة عن ملف XML الذي يقدم تعليمات حول إجراء الاختبار (أو الاختبارات) المطلوب إجراؤها، ومعرفة الوحدات الأخرى المطلوب تنفيذها طلبك.

لنبدأ في إنشاء تهيئة جديدة لـ HelloWorldTest (يرجى ملاحظة الصف الكامل اسم HelloWorldTest):

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
</configuration>

يمكنك حفظ هذه البيانات في ملف helloworld.xml في أي مكان على جهازك. نظام الملفات (مثل /tmp/helloworld.xml). سيقوم TF بتحليل ملف XML الخاص بالإعداد (المعروف أيضًا باسم الضبط)، حمّل الفئة المحددة باستخدام الانعكاس، وإنشاء مثيل له، وتحويله إلى IRemoteTest، واستدعاء run.

تنفيذ الإعداد (R)

من واجهة المستخدم، ابدأ تشغيل وحدة التحكّم المبادلة:

tradefed.sh

يُرجى التأكُّد من اتصال الجهاز بالجهاز المضيف ورؤيته للمقايضة:

tf> list devices
Serial            State      Product   Variant   Build   Battery
004ad9880810a548  Available  mako      mako      JDQ39   100

يمكن تنفيذ الإعدادات باستخدام run <config> وحدة التحكم. ننصحك بما يلي:

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!

من المفترض أن تظهر لك رسالة "مرحبًا، الناتج في الوحدة الطرفية.

يمكنك التأكّد من تنفيذ أحد الأوامر باستخدام 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 نفسها. تتعرف أداة تبديل الوظيفة تلقائيًا على جميع الإعدادات الموضوعة في config على مسار classpath.

للتوضيح، انقل ملف helloworld.xml إلى ملف التبادل. المكتبة الأساسية (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml). أعدت تداول العملات، وأعد تشغيل وحدة التحكم المتداولة، ثم اطلب من trackfed عرض قائمة الإعدادات من 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. مقايضة هو إجراء اختبارات باستخدام أجهزة 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.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

من المفترض أن تظهر رسالة الطباعة الجديدة التي تعرض الرقم التسلسلي الخاص بك.

إرسال نتائج الاختبار (D)

تبلّغ 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 التي يمكنك إعادة استخدامها. بدلاً من كتابة وصفك من البداية على سبيل المثال: اختبار قياس حالة التطبيق إجراء اختبارات أحد تطبيقات Android عن بُعد على جهاز Android وتحليل النتائج، وإعادة توجيه هذه النتائج إلى ITestInvocationListener). للحصول على التفاصيل، يمكنك مراجعة الاختبار الأنواع:

نتائج اختبار المتجر (I)

يتم تنفيذ أداة استماع الاختبار التلقائية لتهيئة TF: TextResultReporter، وهو ما يؤدي إلى تفريغ نتائج الاستدعاء إلى البيانات الثابتة. للتوضيح، قم بتشغيل إعدادات 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 بتنسيق مشابه لذلك يستخدمه كاتب ant JUnit XML. لتحديد results_reporter في الإعداد، تعديل …/res/config/example/helloworld.xml الإعداد:

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
    <result_reporter class="com.android.tradefed.result.XmlResultReporter" />
</configuration>

الآن أعد بناء نموذج hello world وإعادة تشغيل نموذج 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 من واجهة pyplot.

يدعم تطبيق Tradefed العديد من المستمعين للاستدعاء، حتى تتمكن من إرسال نتائج الاختبار إلى وجهات مستقلة متعددة للقيام بذلك، حدد فقط خيارات علامات <result_reporter> في الإعدادات.

مرافق قطع الأشجار (د، ي، ر)

تشمل مرافق التسجيل الخاصة بـ "TF" القدرة على:

  1. التقاط السجلّات من الجهاز (المعروف أيضًا باسم Logcat)
  2. تسجيل السجلات من إطار عمل اتحاد التجارة الذي يعمل على الجهاز المضيف (يُعرف أيضًا بسجلّ المضيف)

يلتقط إطار عمل TF تلقائيًا ملف Logcat من الجهاز المخصّص. وترسلها إلى مستمع الاستدعاء لمعالجتها بعد ذلك، يحفظ XmlResultReporter ملف Logcat الذي تم التقاطه للجهاز.

يتم الإبلاغ عن سجلات مضيف TF باستخدام برنامج تضمين CLog لفئة سجل 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 وإعادة تشغيله، يجب أن ترى تسجيل رسالة على stdout:

tf> run example/helloworld
…
05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
…

بشكل تلقائي، يتم تبادل إخراج سجل المضيف الرسائل إلى 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 ضمن التكوين عن طريق إضافة العنصر <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 بعد أن تم التبديل إلى استخدام 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

هذا كل شيء يا رفاق!

للتذكير، إذا واجهتك مشكلة ما، فإن تجارة يحتوي رمز مصدر الاتحاد على الكثير من المعلومات المفيدة التي لا يتم الكشف عنها في الوثائق. إذا لم ينجح كل ما سبق، يمكنك طرحه على نظام التشغيل Android مجموعة Google، مع "اتحاد تجاري" في موضوع الرسالة.