هنگامی که یک تست ابزار دقیق شروع می شود، بسته هدف آن با تزریق کد ابزار دقیق راه اندازی مجدد می شود و برای اجرا آغاز می شود. یک استثنا این است که بسته مورد نظر در اینجا نمی تواند خود فریم ورک برنامه اندروید باشد، مانند بسته 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
داشته باشد، زیرا نیاز به بستهبندی مجموعههای مختلف آزمایش در 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
استفاده می کنید.
توجه داشته باشید که اگرچه نام بسته معمولاً به همان سبک نام بسته جاوا است، اما در واقع موارد بسیار کمی با آن انجام می شود. به عبارت دیگر، بسته برنامه (یا آزمایش) شما ممکن است شامل کلاس هایی با هر نام بسته باشد، اگرچه از طرف دیگر، می توانید سادگی را انتخاب کنید و نام بسته جاوای سطح بالای خود را در برنامه یا تست خود با نام بسته برنامه یکسان داشته باشید.
android:sharedUserId="android.uid.system"
این نشان میدهد که در زمان نصب، به این فایل APK باید همان شناسه کاربری، یعنی هویت زمان اجرا، به عنوان پلتفرم اصلی داده شود. توجه داشته باشید که این بستگی به این دارد که apk با گواهینامه مشابه با پلتفرم اصلی امضا شود (به LOCAL_CERTIFICATE
در بخش قبلی مراجعه کنید)، اما آنها مفاهیم متفاوتی هستند:
- برخی از مجوزها یا APIها با امضا محافظت می شوند که به گواهی امضای یکسانی نیاز دارد
- برخی از مجوزها یا APIها به هویت کاربر
system
تماس گیرنده نیاز دارند، که بسته تماس گیرنده باید شناسه کاربر را باsystem
به اشتراک بگذارد، در صورتی که بسته جداگانه ای از خود پلت فرم اصلی باشد.
<uses-library android:name="android.test.runner" />
این برای تمام تستهای ابزار دقیق مورد نیاز است، زیرا کلاسهای مرتبط در یک فایل کتابخانه JAR چارچوب جداگانه بستهبندی میشوند، بنابراین زمانی که بسته آزمایشی توسط چارچوب برنامه فراخوانی میشود، به ورودیهای مسیر کلاس اضافی نیاز دارد.
android:targetPackage="android.test.example.helloworld"
شاید متوجه شده باشید که targetPackage
در اینجا همانند ویژگی package
اعلام شده در تگ manifest
این فایل اعلام شده است. همانطور که در مبانی تست ذکر شد، این دسته از تست های ابزار دقیق معمولاً برای آزمایش API های چارچوب در نظر گرفته شده اند، بنابراین داشتن یک بسته برنامه هدفمند خاص، غیر از خود، برای آنها چندان معنی دار نیست.
فایل پیکربندی ساده
هر ماژول آزمایشی جدید باید یک فایل پیکربندی برای هدایت سیستم ساخت با فراداده های ماژول، وابستگی های زمان کامپایل و دستورالعمل های بسته بندی داشته باشد. در بیشتر موارد، گزینه فایل Blueprint مبتنی بر Soong کافی است. برای جزئیات، به پیکربندی آزمایش ساده مراجعه کنید.
فایل پیکربندی پیچیده
برای این موارد پیچیده تر، همچنین باید یک فایل پیکربندی آزمایشی برای مهار تست اندروید، 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 مشخص شده روی دستگاه مورد نظر نصب کند. آمادهکنندههای هدف زیادی در اختیار توسعهدهندگان در فدراسیون تجاری هستند و میتوان از آنها برای اطمینان از راهاندازی صحیح دستگاه قبل از اجرای آزمایش استفاده کرد.
<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 را مشخص میکند تا از آن برای اجرای تست استفاده شود و در بسته روی دستگاهی که باید اجرا شود و چارچوب تست runner که در این مورد JUnit است را پاس میکند.
برای اطلاعات بیشتر، تنظیمات ماژول تست را ببینید.
ویژگی های JUnit4
استفاده از کتابخانه android-support-test
به عنوان اجرای آزمایشی، پذیرش کلاسهای تست سبک JUnit4 جدید را امکانپذیر میسازد، و نمونه تغییر گریت حاوی برخی استفادههای بسیار اساسی از ویژگیهای آن است. مثال را در /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java ببینید.
در حالی که الگوهای آزمایشی معمولاً مختص تیم های جزء هستند، برخی از الگوهای استفاده به طور کلی مفید هستند.
@RunWith(JUnit4.class)
public class HelloWorldTest {
یک تفاوت قابل توجه در JUnit4 این است که دیگر نیازی به ارث بردن از یک کلاس تست پایه مشترک نیست. در عوض، تستها را در کلاسهای جاوا ساده مینویسید و از حاشیهنویسی برای نشان دادن تنظیمات و محدودیتهای تست خاص استفاده میکنید. در این مثال، ما دستور می دهیم که این کلاس باید به عنوان یک تست 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
حاشیه نویسی شوند. طبق معمول، روشهای تست باید عمومی باشند، هیچ مقدار بازگشتی را اعلام نکنند، هیچ پارامتری دریافت نکنند و ممکن است استثناهایی ایجاد کنند.
دسترسی به کلاس ابزار دقیق
اگرچه در مثال اولیه hello world پوشش داده نشده است، اما معمولاً برای یک تست Android به نمونه Instrumentation
دسترسی نیاز است: این رابط API اصلی است که دسترسی به زمینه های برنامه، API های تست مربوط به چرخه عمر فعالیت و موارد دیگر را فراهم می کند.
از آنجایی که تستهای JUnit4 دیگر نیازی به کلاس پایه مشترک ندارند، دیگر نیازی به بدست آوردن نمونه Instrumentation
از طریق InstrumentationTestCase#getInstrumentation()
نیست، در عوض، اجراکننده آزمایشی جدید آن را از طریق InstrumentationRegistry
مدیریت میکند که در آن تنظیمات محیطی و متنی ایجاد شده توسط چارچوب ابزار دقیق ذخیره میشود.
برای دسترسی به نمونه کلاس Instrumentation
، به سادگی متد static getInstrumentation()
را در کلاس InstrumentationRegistry
فراخوانی کنید:
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
به صورت محلی بسازید و آزمایش کنید
برای رایج ترین موارد استفاده، از Atest استفاده کنید.
برای موارد پیچیدهتر که نیاز به سفارشیسازی سنگینتر دارند، دستورالعملهای ابزار دقیق را دنبال کنید.