مثال آزمایش‌های خودابزارگری

وقتی آزمایش ابزار دقیق شروع می‌شود، بسته هدف آن با کد ابزار دقیق تزریق‌شده و برای اجرا شروع می‌شود. یک استثنا این است که بسته هدف در اینجا نمی‌تواند چارچوب برنامه Android باشد، مثلاً بسته android، زیرا انجام این کار منجر به وضعیت متناقضی می‌شود که در آن چارچوب Android باید مجدداً راه‌اندازی شود، که همان چیزی است که از عملکردهای سیستم، ازجمله خود ابزار دقیق، پشتیبانی می‌کند.

این یعنی آزمون ابزاربندی نمی‌تواند برای اجرا خود را به چارچوب Android، که با نام سرور سیستم نیز شناخته می‌شود، تزریق کند. برای آزمایش چارچوب Android، کد آزمایش فقط می‌تواند سطوح میانای برنامه‌سازی کاربردی عمومی یا سطوحی را که بااستفاده از زبان تعریف واسط Android AIDL در درخت منبع پلاتفرم نمایان شده‌اند فراخوانی کند. برای این دسته از آزمایش‌ها، هدف‌یابی بسته خاصی معنا ندارد. بنابراین، معمولاً چنین ابزارهایی برای هدف‌یابی بسته برنامه آزمایشی خودشان، همان‌طور که در برچسب <manifest> از AndroidManifest.xml تعریف شده است، اعلام می‌شوند.

بسته به الزامات، بسته‌های برنامه آزمایشی در این دسته ممکن است همچنین:

  • فعالیت‌های بسته برای آزمایش لازم است.
  • شناسه کاربر را با سیستم هم‌رسانی کنید.
  • با کلید پلاتفرم امضا شده باشد.
  • به‌جای کیت توسعه نرم‌افزار عمومی، دربرابر منبع چارچوب کامپایل شود.

این دسته از آزمایش‌های ابزارگری گاهی اوقات با عنوان خودابزارگری شناخته می‌شود. در اینجا چند نمونه از آزمایش‌های خودابزار در منبع پلاتفرم آورده شده است:

مثالی که در اینجا پوشش داده شده است نوشتن یک تست ابزار دقیق جدید با بسته هدف است که در بسته برنامه تست خود تنظیم شده است. این راهنما از آزمون زیر به‌عنوان مثال استفاده می‌کند:

توصیه می‌شود ابتدا کد را مرور کنید تا پیش‌از ادامه دادن، تصوری کلی از آن داشته باشید.

درباره مکان منبع تصمیم بگیرید

معمولاً تیم شما ازقبل الگوی ثابتی از مکان‌هایی برای بررسی در کد و مکان‌هایی برای افزودن آزمایش دارد. اکثر تیم‌ها مالک یک مخزن 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" />

این کار برای همه آزمایش‌های «ابزار دقیق» الزامی است زیرا کلاس‌های مربوطه در فایل کتابخانه 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>

این کلاس آزمایشی «فدراسیون تجارت» را که برای اجرای آزمون استفاده می‌شود مشخص می‌کند و بسته را در دستگاه برای اجرا و چارچوب اجراکننده آزمون که در این مورد 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 حاشیه‌نویسی شود. طبق معمول، روش‌های آزمایش باید عمومی باشند، مقدار برگشتی اعلام نکنند، پارامتر نگیرند، و ممکن است استثناهایی را ایجاد کنند.

دسترسی کلاس ابزار دقیق

اگرچه در مثال ساده «سلام دنیا» پوشش داده نشده است، اما معمولاً آزمایش Android به دسترسی به نمونه Instrumentation نیاز دارد: این میانای برنامه‌سازی کاربردی اصلی است که دسترسی به زمینه‌های برنامه، میاناهای برنامه‌سازی کاربردی آزمایش مرتبط با چرخه حیات فعالیت، و موارد دیگر را فراهم می‌کند.

ازآنجایی‌که آزمایش‌های JUnit4 دیگر به کلاس پایه مشترک نیاز ندارد، دیگر لازم نیست نمونه Instrumentation را ازطریق InstrumentationTestCase#getInstrumentation() دریافت کنید، درعوض، اجراکننده آزمایش جدید آن را ازطریق InstrumentationRegistry مدیریت می‌کند، جایی که راه‌اندازی زمینه‌ای و محیطی ایجادشده توسط چارچوب ابزار دقیق در آن ذخیره می‌شود.

برای دسترسی به نمونه کلاس Instrumentation، کافی است روش ثابت getInstrumentation() را در کلاس InstrumentationRegistry فراخوانی کنید:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

ساختن و آزمایش محلی

برای رایج‌ترین موارد استفاده، از Atest استفاده کنید.

برای موارد پیچیده‌تر که نیاز به سفارشی‌سازی سنگین‌تر دارند، دستورالعمل‌های ابزاربندی را دنبال کنید.