أمثلة على اختبارات القياس الذاتي

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

وهذا يعني أن اختبار الأجهزة لا يمكن إدخاله في إطار عمل Android، المعروف أيضًا باسم خادم النظام، من أجل التنفيذ. من أجل اختبار إطار عمل Android، يمكن لرمز الاختبار استدعاء أسطح API العامة فقط، أو تلك التي يتم عرضها باستخدام لغة تعريف واجهة Android AIDL المتوفرة في شجرة مصدر النظام الأساسي. بالنسبة لهذه الفئة من الاختبارات، ليس من المفيد استهداف أي حزمة معينة. لذلك، من المعتاد أن يتم الإعلان عن أن هذه الأدوات تستهدف حزمة تطبيق الاختبار الخاصة بها، كما هو محدد في علامة <manifest> الخاصة بها في AndroidManifest.xml .

اعتمادًا على المتطلبات، قد تكون حزم تطبيقات الاختبار في هذه الفئة أيضًا:

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

يُشار أحيانًا إلى هذه الفئة من اختبارات الأجهزة باسم الأجهزة الذاتية. فيما يلي بعض الأمثلة على اختبارات الأجهزة الذاتية في مصدر النظام الأساسي:

المثال المغطى هنا هو كتابة اختبار أجهزة جديد مع تعيين الحزمة المستهدفة في حزمة تطبيق الاختبار الخاصة بها. يستخدم هذا الدليل الاختبار التالي ليكون بمثابة مثال:

يوصى بتصفح الكود أولاً للحصول على انطباع تقريبي قبل المتابعة.

اتخاذ قرار بشأن موقع المصدر

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

بافتراض أن الموقع الجذر لمصدر المكون الخاص بك هو <component source root> ، فإن معظم المكونات تحتوي على مجلدات src ومجلدات tests تحتها، وبعض الملفات الإضافية مثل Android.mk (أو مقسمة إلى ملفات .mk إضافية)، وملف البيان AndroidManifest.xml وملف التكوين الاختباري "AndroidTest.xml".

نظرًا لأنك تضيف اختبارًا جديدًا، فربما ستحتاج إلى إنشاء دليل tests بجوار المكون src وتعبئته بالمحتوى.

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

بغض النظر عن البنية، سينتهي بك الأمر إلى ملء دليل tests أو الدليل الفرعي الذي تم إنشاؤه حديثًا بملفات مشابهة لما هو موجود في دليل instrumentation في نموذج تغيير gerrit. سيتم شرح تفاصيل كل ملف لاحقًا في هذه الوثيقة.

ملف البيان

كما هو الحال مع مشروع التطبيق، تتطلب كل وحدة اختبار للأجهزة ملف بيان يسمى AndroidManifest.xml . لتضمين هذا الملف تلقائيًا باستخدام الملف الأساسي BUILD_PACKAGE ، قم بتوفير هذا الملف بجوار ملف Android.mk لوحدة الاختبار الخاصة بك.

إذا لم تكن على دراية بملف AndroidManifest.xml ، فارجع إلى نظرة عامة على بيان التطبيق

فيما يلي نموذج لملف AndroidManifest.xml :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

حدد البعض الملاحظات في ملف البيان:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

سمة package هي اسم حزمة التطبيق: هذا هو المعرف الفريد الذي يستخدمه إطار عمل تطبيق Android لتحديد التطبيق (أو في هذا السياق: تطبيق الاختبار الخاص بك). يمكن لكل مستخدم في النظام تثبيت تطبيق واحد فقط يحمل اسم الحزمة هذا.

علاوة على ذلك، فإن سمة package هذه هي نفس ما يُرجعه ComponentName#getPackageName() ، وأيضًا نفس الشيء الذي ستستخدمه للتفاعل مع مختلف أوامر pm الفرعية التي تستخدم adb shell .

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

android:sharedUserId="android.uid.system"

يوضح هذا أنه في وقت التثبيت، يجب منح ملف APK هذا نفس معرف المستخدم، أي هوية وقت التشغيل، مثل النظام الأساسي الأساسي. لاحظ أن هذا يعتمد على توقيع ملف apk بنفس شهادة النظام الأساسي (راجع LOCAL_CERTIFICATE في القسم السابق)، إلا أنهما مفهومان مختلفان:

  • بعض الأذونات أو واجهات برمجة التطبيقات محمية بالتوقيع، الأمر الذي يتطلب نفس شهادة التوقيع
  • تتطلب بعض الأذونات أو واجهات برمجة التطبيقات هوية مستخدم system للمتصل، الأمر الذي يتطلب من حزمة الاتصال مشاركة معرف المستخدم مع system ، إذا كانت حزمة منفصلة عن النظام الأساسي نفسه
<uses-library android:name="android.test.runner" />

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

android:targetPackage="android.test.example.helloworld"

ربما لاحظت أنه تم الإعلان عن targetPackage هنا بنفس سمة package المعلنة في علامة manifest لهذا الملف. كما هو مذكور في أساسيات الاختبار ، فإن هذه الفئة من اختبارات الأجهزة مخصصة عادةً لاختبار واجهات برمجة التطبيقات لإطار العمل، لذلك ليس من المفيد جدًا أن يكون لديهم حزمة تطبيقات مستهدفة محددة، بخلاف حزمة التطبيقات نفسها.

ملف التكوين البسيط

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

ملف التكوين المعقد

بالنسبة لهذه الحالات الأكثر تعقيدًا، تحتاج أيضًا إلى كتابة ملف تكوين اختباري لأداة اختبار Android، Trade Union .

يمكن لتكوين الاختبار تحديد خيارات إعداد الجهاز الخاصة والوسائط الافتراضية لتوفير فئة الاختبار. راجع المثال على /platform_testing/tests/example/instrumentation/AndroidTest.xml .

يتم تضمين لقطة هنا للراحة:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

حدد بعض الملاحظات على ملف تكوين الاختبار:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

هذا يخبر الاتحاد التجاري بتثبيت HelloWorldTests.apk على الجهاز المستهدف باستخدام target_preparer المحدد. هناك العديد من أدوات إعداد الأهداف المتاحة للمطورين في الاتحاد التجاري ويمكن استخدامها لضمان إعداد الجهاز بشكل صحيح قبل تنفيذ الاختبار.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

يحدد هذا فئة اختبار الاتحاد التجاري المراد استخدامه لتنفيذ الاختبار ويمرر في الحزمة الموجودة على الجهاز المراد تنفيذه وإطار تشغيل الاختبار الذي هو JUnit في هذه الحالة.

لمزيد من المعلومات، راجع تكوينات وحدة الاختبار .

مميزات JUnit4

يتيح استخدام مكتبة android-support-test كمشغل اختبار اعتماد فئات اختبار نمط JUnit4 الجديدة، ويحتوي نموذج تغيير gerrit على بعض الاستخدامات الأساسية جدًا لميزاته. راجع المثال على /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java .

على الرغم من أن أنماط الاختبار تكون عادةً خاصة بالفرق المكونة، إلا أن هناك بعض أنماط الاستخدام المفيدة بشكل عام.

@RunWith(JUnit4.class)
public class HelloWorldTest {

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

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

يتم استخدام التعليقات التوضيحية @Before و @After في الطرق بواسطة JUnit4 لإجراء إعداد الاختبار المسبق وتفكيك الاختبار اللاحق. وبالمثل، يتم استخدام التعليقات التوضيحية @BeforeClass و @AfterClass في الأساليب بواسطة JUnit4 لإجراء الإعداد قبل تنفيذ جميع الاختبارات في فئة الاختبار، والتفكيك بعد ذلك. لاحظ أن أساليب الإعداد والتفكيك لنطاق الفصل يجب أن تكون ثابتة. أما بالنسبة لطرق الاختبار، على عكس الإصدار السابق من JUnit، فإنها لم تعد بحاجة إلى بدء اسم الطريقة بـ test ، وبدلاً من ذلك، يجب إضافة تعليق توضيحي لكل منها بـ @Test . كالعادة، يجب أن تكون طرق الاختبار عامة، ولا تعلن عن قيمة إرجاع، ولا تأخذ أي معلمات، وقد تطرح استثناءات.

الوصول إلى فئة الأجهزة

على الرغم من عدم تناول مثال helloworld الأساسي، إلا أنه من الشائع جدًا أن يتطلب اختبار Android الوصول إلى مثيل Instrumentation : هذه هي واجهة API الأساسية التي توفر الوصول إلى سياقات التطبيق وواجهات برمجة التطبيقات ذات الصلة بدورة حياة النشاط والمزيد.

نظرًا لأن اختبارات JUnit4 لم تعد تتطلب فئة أساسية مشتركة، لم يعد من الضروري الحصول على مثيل Instrumentation عبر InstrumentationTestCase#getInstrumentation() ، وبدلاً من ذلك، يقوم مشغل الاختبار الجديد بإدارته عبر InstrumentationRegistry حيث يتم تخزين الإعداد السياقي والبيئي الذي تم إنشاؤه بواسطة إطار عمل الأجهزة.

للوصول إلى مثيل فئة Instrumentation ، ما عليك سوى استدعاء الأسلوب الثابت getInstrumentation() في فئة InstrumentationRegistry :

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

بناء واختبار محليا

بالنسبة لحالات الاستخدام الأكثر شيوعًا، استخدم Atest .

بالنسبة للحالات الأكثر تعقيدًا التي تتطلب تخصيصًا أكبر، اتبع تعليمات الأجهزة .