عند بدء اختبار الأجهزة، تتم إعادة تشغيل الحزمة المستهدَفة مع إدخال رمز الأجهزة وبدء تنفيذه. أحد الاستثناءات هو أنّه لا يمكن أن تكون الحزمة المستهدَفة هنا هي إطار عمل تطبيق Android نفسه، مثل الحزمة android
، لأنّ ذلك يؤدي إلى حالة متناقضة حيث يجب إعادة تشغيل إطار عمل Android، وهو ما يتيح وظائف النظام، بما في ذلك أداة القياس نفسها.
وهذا يعني أنّه لا يمكن لأحد اختبارات الأدوات إدخال نفسه في إطار عمل Android، المعروف أيضًا باسم خادم النظام، لتنفيذه. ولاختبار إطار عمل Android، يمكن لرمز الاختبار استدعاء واجهات برمجة التطبيقات العامة فقط أو تلك التي يتم عرضها باستخدام لغة تعريف واجهة Android (Android Interface Definition Language) 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
إلى كل طريقة. وكالعادة، يجب أن تكون طرق الاختبار عامة، وألا تحدّد قيمة معروضة، وألا تأخذ أي مَعلمات،
ويجوز أن تعرض استثناءات.
إذن الوصول إلى فئة أدوات القياس
على الرغم من أنّ مثال "hello world" الأساسي لا يتضمّن ذلك، إلا أنّه من الشائع جدًا أن يتطلّب اختبار Android الوصول إلى مثيل Instrumentation
، وهو واجهة برمجة التطبيقات الأساسية التي تتيح الوصول إلى سياقات التطبيقات وواجهات برمجة التطبيقات للاختبار ذات الصلة بدورة حياة النشاط وغير ذلك.
بما أنّ اختبارات JUnit4 لم تعُد تتطلّب فئة أساسية مشتركة، لم يعُد من الضروري الحصول على مثيل Instrumentation
من خلال InstrumentationTestCase#getInstrumentation()
، بل يديره مشغّل الاختبار الجديد من خلال InstrumentationRegistry
حيث يتم تخزين الإعداد السياقي والبيئي الذي تم إنشاؤه بواسطة إطار عمل أدوات القياس.
للوصول إلى مثيل الفئة Instrumentation
، ما عليك سوى استدعاء الطريقة الثابتة
getInstrumentation()
في الفئة InstrumentationRegistry
:
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
إنشاء التطبيق واختباره محليًا
بالنسبة إلى حالات الاستخدام الأكثر شيوعًا، استخدِم Atest.
بالنسبة إلى الحالات الأكثر تعقيدًا التي تتطلّب تخصيصًا أكبر، اتّبِع تعليمات القياس.