عند بدء اختبار لقياس حالة التطبيق، تتم إعادة تشغيل الحزمة المستهدَفة مع إدخال رمز قياس حالة التطبيق وبدء تنفيذه. ويُستثنى من ذلك حزمة التطبيق المستهدَفة التي لا يمكن أن تكون إطار عمل تطبيق Android نفسه، مثل الحزمة android، لأنّ ذلك يؤدي إلى حالة متناقضة حيث يجب إعادة تشغيل إطار عمل Android، وهو ما يتيح وظائف النظام، بما في ذلك أداة القياس نفسها.
وهذا يعني أنّه لا يمكن لاختبار لقياس حالة التطبيق إدخال نفسه في إطار عمل Android، المعروف أيضًا باسم خادم النظام، لتنفيذه. ولاختبار إطار عمل Android، يمكن لرمز الاختبار استدعاء واجهات برمجة التطبيقات العامة فقط أو تلك التي يتم عرضها باستخدام لغة تعريف واجهة نظام Android AIDL المتوفّرة في شجرة مصدر النظام الأساسي. بالنسبة إلى هذه الفئة من الاختبارات، ليس من المفيد استهداف أي حزمة معيّنة. لذلك، من المعتاد أن يتم الإعلان عن أدوات القياس هذه لاستهداف حزمة تطبيق الاختبار الخاصة بها، كما هو محدّد في علامة <manifest> الخاصة بها ضمن AndroidManifest.xml.
بناءً على المتطلبات، قد تتضمّن حِزم التطبيقات الاختبارية في هذه الفئة أيضًا ما يلي:
- أنشطة الحزمة المطلوبة للاختبار
- شارِك رقم تعريف المستخدم مع النظام.
- أن يتم توقيعها باستخدام مفتاح النظام الأساسي
- يجب أن يتم تجميعها باستخدام مصدر إطار العمل بدلاً من حزمة SDK العامة.
يُشار أحيانًا إلى هذه الفئة من اختبارات القياس باسم القياس الذاتي. في ما يلي بعض الأمثلة على اختبارات القياس الذاتي في رمز مصدر النظام الأساسي:
المثال الذي سنتناوله هنا هو كتابة اختبار لقياس حالة التطبيق جديد مع ضبط حزمة الاستهداف على حزمة تطبيق الاختبار الخاصة بها. يستخدم هذا الدليل الاختبار التالي كمثال:
ننصحك بتصفّح الرمز أولاً للحصول على فكرة عامة قبل المتابعة.
تحديد الموقع الجغرافي المصدر
عادةً، يكون لدى فريقك نمط محدّد من الأماكن التي يجب التحقّق منها في الرمز البرمجي، والأماكن التي يجب إضافة الاختبارات إليها. تمتلك معظم الفِرق مستودع git واحدًا، أو تشارك مستودعًا واحدًا مع فِرق أخرى ولكن لديها دليل فرعي مخصّص يحتوي على رمز مصدر المكوّن.
بافتراض أنّ الموقع الجذري لمصدر المكوّن هو <component source
root>، تحتوي معظم المكوّنات على المجلّدَين src وtests ضمنه، وبعض الملفات الإضافية، مثل Android.mk (أو مقسّمًا إلى ملفات .mk إضافية)، وملف البيان AndroidManifest.xml، وملف إعداد الاختبار AndroidTest.xml.
بما أنّك ستضيف اختبارًا جديدًا تمامًا، من المحتمل أن تحتاج إلى إنشاء دليل tests بجانب المكوّن src، وملء الدليل بالمحتوى.
في بعض الحالات، قد يتضمّن فريقك المزيد من بنى الدليل ضمن tests
بسبب الحاجة إلى تجميع مجموعات مختلفة من الاختبارات في حِزم APK فردية. وفي هذه الحالة، عليك إنشاء دليل فرعي جديد ضمن 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" />
هذا الإعداد مطلوب لجميع اختبارات Instrumentation، لأنّ الفئات ذات الصلة يتم تجميعها في ملف مكتبة JAR منفصل، وبالتالي يتطلّب إدخالات إضافية في مسار الفئة عند استدعاء حزمة الاختبار من خلال إطار عمل التطبيق.
android:targetPackage="android.test.example.helloworld"
ربما لاحظت أنّ targetPackage هنا تم تعريفه بالطريقة نفسها التي تم بها تعريف السمة package في العلامة manifest لهذا الملف. كما هو مذكور في أساسيات الاختبار، تهدف هذه الفئة من اختبارات قياس حالة التطبيق إلى اختبار واجهات برمجة التطبيقات الخاصة بإطار العمل، لذا ليس من المنطقي أن يكون لها حزمة تطبيق مستهدَفة معيّنة، بخلاف الحزمة الخاصة بها.
ملف إعداد بسيط
يجب أن يحتوي كل نموذج اختبار جديد على ملف إعداد لتوجيه نظام الإنشاء باستخدام البيانات الوصفية للوحدة النمطية والتبعيات في وقت الترجمة وتعليمات التعبئة. في معظم الحالات، يكون خيار ملف Blueprint المستند إلى Soong كافيًا. لمزيد من التفاصيل، يُرجى الاطّلاع على إعداد الاختبار البسيط.
ملف إعداد معقّد
في هذه الحالات الأكثر تعقيدًا، عليك أيضًا كتابة ملف إعداد اختبار لأداة اختبار Android، Trade Federation.
يمكن أن يحدّد إعداد الاختبار خيارات خاصة بإعداد الجهاز والحجج التلقائية لتوفير فئة الاختبار. راجِع المثال على /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>
يطلب هذا الأمر من Trade Federation تثبيت HelloWorldTests.apk على الجهاز المستهدَف باستخدام target_preparer محدّد. يتوفّر العديد من أدوات إعداد الأهداف للمطوّرين في Trade Federation، ويمكن استخدامها لضمان إعداد الجهاز بشكل صحيح قبل تنفيذ الاختبار.
<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>
يحدّد هذا الأمر فئة اختبار Trade Federation التي سيتم استخدامها لتنفيذ الاختبار، كما يمرّر الحزمة على الجهاز المطلوب تنفيذها وإطار عمل مشغّل الاختبار، وهو 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 لإجراء عملية الإعداد قبل تنفيذ جميع الاختبارات في فئة الاختبار، وعملية الإزالة بعد ذلك. يُرجى العِلم أنّ طرق الإعداد والإيقاف على مستوى الفئة يجب أن تكون ثابتة. أما بالنسبة إلى طرق الاختبار،
فلم يعُد من الضروري أن يبدأ اسم الطريقة
بالرمز test، كما كان الحال في الإصدارات السابقة من JUnit،
بل يجب بدلاً من ذلك إضافة التعليق التوضيحي @Test إلى كل طريقة. وكالعادة، يجب أن تكون طرق الاختبار عامة، وألا تعلن عن أي قيمة إرجاع، وألا تأخذ أي معلَمات، ويجوز لها طرح استثناءات.
أذونات الوصول إلى فئة أدوات القياس
على الرغم من أنّ مثال "مرحبًا بالعالم" الأساسي لا يتضمّن ذلك، إلا أنّه من الشائع جدًا أن يتطلّب اختبار Android الوصول إلى مثيل Instrumentation، وهو واجهة برمجة التطبيقات الأساسية التي تتيح الوصول إلى سياقات التطبيقات وواجهات برمجة التطبيقات الخاصة بالاختبارات المرتبطة بدورة حياة الأنشطة وغير ذلك.
بما أنّ اختبارات JUnit4 لم تعُد تتطلّب صنفًا أساسيًا مشتركًا، لم يعُد من الضروري الحصول على مثيل Instrumentation من خلال InstrumentationTestCase#getInstrumentation()، بل يديره مشغّل الاختبار الجديد من خلال InstrumentationRegistry حيث يتم تخزين الإعداد السياقي والبيئي الذي تم إنشاؤه بواسطة إطار عمل قياس حالة التطبيق.
للوصول إلى مثيل الفئة Instrumentation، ما عليك سوى استدعاء الطريقة الثابتة
getInstrumentation() في الفئة InstrumentationRegistry:
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
إنشاء التطبيق واختباره محليًا
في حالات الاستخدام الأكثر شيوعًا، استخدِم Atest.
بالنسبة إلى الحالات الأكثر تعقيدًا التي تتطلّب تخصيصًا أكبر، اتّبِع تعليمات القياس.