כשמתחילים בדיקת אינסטרומנטציה, חבילת היעד שלה מופעלת מחדש עם קוד אינסטרומנטציה שמוזרק ומופעל לצורך ביצוע. יוצא מן הכלל הוא שחבילת היעד כאן לא יכולה להיות מסגרת אפליקציה ל-Android עצמה, כמו החבילה android, כי פעולה כזו מובילה למצב פרדוקסלי שבו צריך להפעיל מחדש את מסגרת Android, שהיא מה שתומך בפונקציות המערכת, כולל האינסטרומנטציה עצמה.
כלומר, בדיקת אינסטרומנטציה לא יכולה להזריק את עצמה למסגרת Android, כלומר לשרת המערכת, לצורך ביצוע. כדי לבדוק את מסגרת Android, קוד הבדיקה יכול להפעיל רק ממשקי API ציבוריים, או ממשקי API שנחשפים באמצעות 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. כדי לכלול את הקובץ הזה באופן אוטומטי באמצעות קובץ ה-makefile הראשי של 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 בקטע הקודם), אבל אלה שני מושגים שונים:
- חלק מההרשאות או ממשקי ה-API מוגנים באמצעות חתימה, ולכן נדרש אישור חתימה זהה
- חלק מההרשאות או ממשקי ה-API דורשים את
systemזהות המשתמש של המתקשר, ולכן החבילה שקוראת לממשק צריכה לשתף את מזהה המשתמש עםsystem, אם היא חבילה נפרדת מהפלטפורמה עצמה.
<uses-library android:name="android.test.runner" />
הדרישה הזו חלה על כל בדיקות ה-Instrumentation, כי המחלקות הקשורות ארוזות בקובץ JAR של ספריית framework נפרדת, ולכן נדרשים רשומות נוספות ב-classpath כשחבילת הבדיקה מופעלת על ידי framework של האפליקציה.
android:targetPackage="android.test.example.helloworld"
יכול להיות ששמתם לב שהערך targetPackage כאן זהה לערך של המאפיין package שמוצהר בתג manifest של הקובץ הזה. כמו שצוין בהסבר על בדיקות, בדיקות אינסטרומנטציה מהסוג הזה מיועדות בדרך כלל לבדיקת ממשקי API של מסגרות, ולכן אין משמעות רבה לכך שיש להן חבילת אפליקציה ספציפית שמיועדת לבדיקה, מלבד חבילת האפליקציה עצמה.
קובץ תצורה פשוט
לכל מודול בדיקה חדש צריך להיות קובץ תצורה שמנחה את מערכת ה-build באמצעות מטא-נתונים של המודול, יחסי תלות בזמן הקומפילציה והוראות אריזה. ברוב המקרים, האפשרות של קובץ 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 כדי לבצע הגדרה לפני הפעלת כל הבדיקות בכיתת בדיקה, ופירוק לאחר מכן. שימו לב: שיטות ההגדרה וההסרה של היקף המחלקה חייבות להיות סטטיות. בגרסה הזו של JUnit, בניגוד לגרסאות קודמות, לא צריך יותר להתחיל את שם השיטה ב-test, אלא צריך להוסיף לכל אחת מהן את ההערה @Test. כמו תמיד, שיטות בדיקה צריכות להיות ציבוריות, לא להצהיר על ערך החזרה, לא לקבל פרמטרים ויכולות להפעיל חריגים.
גישה למחלקת המכשור
למרות שזה לא מופיע בדוגמה הבסיסית של 'שלום עולם', די נפוץ שבדיקת Android דורשת גישה למופע Instrumentation: זהו ממשק ה-API המרכזי שמספק גישה להקשרים של אפליקציות, לממשקי API של בדיקות שקשורים למחזור החיים של פעילות ועוד.
מכיוון שבדיקות JUnit4 לא דורשות יותר מחלקת בסיס משותפת, אין יותר צורך להשיג מופע של Instrumentation באמצעות InstrumentationTestCase#getInstrumentation(). במקום זאת, מנהל הבדיקות החדש מנהל אותו באמצעות InstrumentationRegistry, שבו מאוחסן ההגדרה ההקשרית והסביבתית שנוצרה על ידי מסגרת המכשור.
כדי לגשת למופע של מחלקת Instrumentation, פשוט קוראים לשיטה הסטטית getInstrumentation() במחלקת InstrumentationRegistry:
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
פיתוח ובדיקה באופן מקומי
בתרחישים הנפוצים ביותר, כדאי להשתמש ב-Atest.
במקרים מורכבים יותר שדורשים התאמה אישית נרחבת, צריך לפעול לפי ההוראות להטמעה.