Spectatio یک چارچوب تست متنباز است که برای آزمایش سیستم عامل اندروید خودرو (AAOS) روی دستگاههای واقعی و مجازی توسعه داده شده است. Spectatio رابطهای برنامهنویسی کاربردی (API) را برای آزمایش برنامهها روی دستگاه خودرو فراهم میکند و یک راهکار قابل توسعه و مقیاسپذیر است که برای تأیید قابلیت و عملکرد AAOS و برنامههای آن استفاده میشود.
طراحی سطح بالا
چارچوب Spectatio برای پیادهسازیهای مختلف رابط کاربری AAOS قابل انطباق و توسعه است. از این چارچوب برای آزمایش قابلیت و عملکرد AAOS روی سختافزار دستگاه، شبیهسازها و محیطهای مجازی استفاده میشود.
شکل زیر طراحی سطح بالای چارچوب Spectatio را توضیح میدهد.

شکل ۱. طراحی سطح بالای چارچوب Spectatio.
چارچوب Spectatio که بر پایه UI Automator ساخته شده است، مجموعهای از APIها را برای ساخت تستهای UI ارائه میدهد که با برنامههای کاربر و سیستم در AAOS تعامل دارند. تستهای خودرو از APIهای ارائه شده توسط چارچوب Spectatio برای تست استفاده میکنند، که این تستها را مستقل از دستگاه تحت تست (DUT) و در صورت پشتیبانی، برای تست دستگاههای مختلف، مقیاسپذیر میکند.
شکل ۱ نشان میدهد که چارچوب Spectatio بر اساس برنامههای مرجع مانند Dialer، Medicenter و Settings با استفاده از رابطها و helperهای مخصوص برنامه، ماژولار شده است و این امر، آن را به راحتی برای برنامههای جدید قابل گسترش میکند. چارچوب Spectatio از کلاسهای کمکی استاندارد و کاربردی رایج استفاده مجدد میکند. کلاس کمکی استاندارد ، کلاس والد برای همه توابع کمکی برنامه است و توابع استانداردی را ارائه میدهد که مختص دستگاه هستند یا در بین برنامهها قابل اجرا هستند. کلاسهای کمکی کاربردی، امکاناتی مانند خواندن یا نوشتن فایلها از دستگاه را ارائه میدهند.
معماری
برای ارائه مجموعهای از APIها برای ساخت تستهای رابط کاربری، چارچوب Spectatio رابطها و کمککنندههای مختص برنامه را پیادهسازی میکند، در حالی که کلاس کمککننده استاندارد موجود را گسترش میدهد و کلاسهای کمککننده کاربردی را وارد میکند.
شکل ۲ معماری سطح بالای چارچوب Spectatio و تمام موجودیتهای دخیل در پیادهسازی APIها برای آزمایش یک برنامه را نشان میدهد.

شکل ۲. معماری سطح بالای چارچوب Spectatio.
رابط کمکی برنامه، طرحی برای پیادهسازی یک کمککننده برنامه ارائه میدهد. این رابط شامل توابع کمکی مختلفی است که برای آزمایش برنامهها مورد نیاز هستند. هر برنامه رابط کاربری مخصوص به خود را دارد، مانند IAutoSettingHelper و IAutoDialHelper . برای اطلاعات بیشتر و فهرست توابع رابط، به توابع رابط کمکی برنامه در AOSP مراجعه کنید.
کلاس کمکی استاندارد شامل ویژگیها و توابع استانداردی است که برای راهاندازی دستگاه مورد نیاز هستند اما مختص هیچ برنامهای نیستند، مانند pressHome و scroll . کلاس کمکی استاندارد در AbstractAutoStandardAppHelper.java تعریف شده است.
کلاسهای کمکی کاربردی توسط فریمورک استفاده میشوند. برای مثال، AutoJsonUtility.java یک کلاس کاربردی است که فایل پیکربندی JSON دستگاه داده شده را بارگذاری میکند و پیکربندیهای فریمورک را در زمان اجرا بهروزرسانی میکند.
ماژول پیادهسازی کمککننده برنامه، هسته اصلی چارچوب Spectatio است. این ماژول شامل پیادهسازی توابع کمکی تعریفشده در رابط کمککننده برنامه است که برای آزمایش برنامهها روی دستگاه خودرو مورد نیاز هستند. هر برنامه پیادهسازی خاص خود را دارد، مانند SettingHelperImpl و DialHelperImpl که توسط تستهای خودرو برای آزمایش برنامهها استفاده میشوند. برای اطلاعات بیشتر و فهرست پیادهسازیها، به توابع پیادهسازی کمککننده برنامه در AOSP مراجعه کنید.
تستهای خودرو از توابع پیادهسازی کمکی برنامه برای آزمایش عملیات مختلف مربوط به برنامه استفاده میکنند. از کلاس HelperAccessor برای دسترسی به توابع پیادهسازی کمکی برنامه استفاده کنید.
کد زیر راهاندازی، پاکسازی و اجرای یک تست نمونه خودرو را نشان میدهد.
@RunWith(AndroidJUnit4.class)
public class AutoApplicationTest {
static HelperAccessor<IAutoApplicationHelper> autoApplicationHelper =
new HelperAccessor<>(IAutoApplicationHelper.class);
public AutoApplicationTest() {
// constructor
// Initialize any attributes that are required for the test execution
}
@Before
public void beforeTest() {
// Initial setup before each test
// For example - open the app
autoApplicationHelper.open();
}
@After
public void afterTest() {
// Cleanup after each test.
// For example - exit the app
autoApplicationHelper.exit();
}
@Test
public void testApplicationFeature() {
// Test
// For example - Test if app is open
assertTrue("Application is not open.", autoApplicationHelper.isOpen());
}
}
سفارشیسازی
چارچوب Spectatio مستقل از رابط کاربری دستگاه است، بنابراین برای آزمایش دستگاههایی با رابطهای کاربری و سختافزارهای متنوع، مقیاسپذیر است. برای دستیابی به این مقیاسپذیری، Spectatio از پیکربندیهای پیشفرض دستگاه بر اساس دستگاه مرجع استفاده میکند. برای پشتیبانی از پیکربندیهای غیر پیشفرض دستگاه، این چارچوب از یک فایل پیکربندی JSON در زمان اجرا برای تنظیم تغییرات رابط کاربری مورد نظر برای دستگاه استفاده میکند. یک فایل پیکربندی JSON از عناصر رابط کاربری مانند TEXT ، DESCRIPTION و RESOURCE_ID به همراه تنظیمات path پشتیبانی میکند و باید فقط شامل اطلاعات مربوط به تغییرات رابط کاربری برای DUT باشد. بقیه عناصر رابط کاربری از مقادیر پیکربندی پیشفرض ارائه شده در چارچوب استفاده میکنند.
تنظیمات پیشفرض دستگاه
فایل پیکربندی JSON نمونه زیر، پیکربندیهای موجود دستگاه و مقادیر پیشفرض آنها را نشان میدهد.
برای نمایش نمونه فایل پیکربندی JSON اینجا کلیک کنید
{ "SETTINGS": { "APPLICATION_CONFIG": { "SETTINGS_TITLE_TEXT": "Settings", "SETTINGS_PACKAGE": "com.android.car.settings", "SETTINGS_RRO_PACKAGE": "com.android.car.settings.googlecarui.rro", "OPEN_SETTINGS_COMMAND": "am start -a android.settings.SETTINGS", "OPEN_QUICK_SETTINGS_COMMAND": "am start -n com.android.car.settings/com.android.car.settings.common.CarSettingActivity" }, "QUICK_SETTINGS": { "OPEN_MORE_SETTINGS": { "TYPE": "RESOURCE_ID", "VALUE": "toolbar_menu_item_1", "PACKAGE": "com.android.car.settings" }, "NIGHT_MODE": { "TYPE": "TEXT", "VALUE": "Night mode" } }, "DISPLAY": { "PATH": "Settings > Display", "OPTIONS": [ "Brightness level" ], "BRIGHTNESS_LEVEL": { "TYPE": "RESOURCE_ID", "VALUE": "seekbar", "PACKAGE": "com.android.car.settings" } }, "SOUND": { "PATH": "Settings > Sound", "OPTIONS": [ "Media volume", "Alarm volume" ] }, "NETWORK_AND_INTERNET": { "PATH": "Settings > Network & internet", "OPTIONS": [ ], "TOGGLE_WIFI": { "TYPE": "RESOURCE_ID", "VALUE": "master_switch", "PACKAGE": "com.android.car.settings" } }, "BLUETOOTH": { "PATH": "Settings > Bluetooth", "OPTIONS": [ ], "TOGGLE_BLUETOOTH": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_menu_item_switch", "PACKAGE": "com.android.car.settings" } }, "APPS_AND_NOTIFICATIONS": { "PATH": "Settings > Apps & notifications", "OPTIONS": [ ], "SHOW_ALL_APPS": { "TYPE": "TEXT", "VALUE": "Show all apps" }, "ENABLE_DISABLE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_menu_item_text", "PACKAGE": "com.android.car.settings" }, "DISABLE_BUTTON_TEXT": { "TYPE": "TEXT", "VALUE": "Disable" }, "ENABLE_BUTTON_TEXT": { "TYPE": "TEXT", "VALUE": "Enable" }, "DISABLE_APP_BUTTON": { "TYPE": "TEXT", "VALUE": "DISABLE APP" }, "FORCE_STOP_BUTTON": { "TYPE": "TEXT", "VALUE": "Force stop" }, "OK_BUTTON": { "TYPE": "TEXT", "VALUE": "OK" }, "PERMISSIONS_MENU": { "TYPE": "TEXT", "VALUE": "Permissions" }, "ALLOW_BUTTON": { "TYPE": "TEXT", "VALUE": "Allow" }, "DENY_BUTTON": { "TYPE": "TEXT", "VALUE": "Deny" }, "DENY_ANYWAY_BUTTON": { "TYPE": "TEXT", "VALUE": "Deny anyway" } }, "DATE_AND_TIME": { "PATH": "Settings > Date & time", "OPTIONS": [ "Automatic date & time", "Automatic time zone" ], "AUTOMATIC_DATE_AND_TIME": { "TYPE": "TEXT", "VALUE": "Automatic date & time" }, "AUTOMATIC_TIME_ZONE": { "TYPE": "TEXT", "VALUE": "Automatic time zone" }, "SET_DATE": { "TYPE": "TEXT", "VALUE": "Set date" }, "SET_TIME": { "TYPE": "TEXT", "VALUE": "Set time" }, "SELECT_TIME_ZONE": { "TYPE": "TEXT", "VALUE": "Select time zone" }, "USE_24_HOUR_FORMAT": { "TYPE": "TEXT", "VALUE": "Use 24-hour format" }, "OK_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "toolbar_menu_item_0", "PACKAGE": "com.android.car.settings" }, "NUMBER_PICKER_WIDGET": { "TYPE": "CLASS", "VALUE": "android.widget.NumberPicker" }, "EDIT_TEXT_WIDGET": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" } }, "USERS": { "PATH": "Settings > Users", "OPTIONS": [ "Guest" ] }, "ACCOUNTS": { "PATH": "Settings > Accounts", "OPTIONS": [ "Automatically sync data" ], "ADD_ACCOUNT": { "TYPE": "TEXT", "VALUE": "ADD ACCOUNT" }, "ADD_GOOGLE_ACCOUNT": { "TYPE": "TEXT", "VALUE": "Google" }, "SIGN_IN_ON_CAR_SCREEN": { "TYPE": "TEXT", "VALUE": "Sign in on car screen" }, "GOOGLE_SIGN_IN_SCREEN": { "TYPE": "TEXT", "VALUE": "Sign in to your Google Account" }, "ENTER_EMAIL": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "ENTER_PASSWORD": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "NEXT_BUTTON": { "TYPE": "TEXT", "VALUE": "Next" }, "DONE_BUTTON": { "TYPE": "TEXT", "VALUE": "Done" }, "REMOVE_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove" }, "REMOVE_ACCOUNT_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove Account" } }, "SYSTEM": { "PATH": "Settings > System", "OPTIONS": [ "About", "Legal information" ], "ABOUT_MENU": { "TYPE": "TEXT", "VALUE": "About" }, "RESET_OPTIONS_MENU": { "TYPE": "TEXT", "VALUE": "Reset options" }, "LANGUAGES_AND_INPUT_MENU": { "TYPE": "TEXT", "VALUE": "Languages & input" }, "DEVICE_MODEL": { "TYPE": "TEXT", "VALUE": "Model" }, "ANDROID_VERSION": { "TYPE": "TEXT", "VALUE": "Android version" }, "ANDROID_SECURITY_PATCH_LEVEL": { "TYPE": "TEXT", "VALUE": "Android security patch level" }, "KERNEL_VERSION": { "TYPE": "TEXT", "VALUE": "Kernel version" }, "BUILD_NUMBER": { "TYPE": "TEXT", "VALUE": "Build number" }, "RECYCLER_VIEW_WIDGET": { "TYPE": "CLASS", "VALUE": "androidx.recyclerview.widget.RecyclerView" }, "RESET_NETWORK": { "TYPE": "TEXT", "VALUE": "Reset network" }, "RESET_SETTINGS": { "TYPE": "TEXT", "VALUE": "RESET SETTINGS" }, "RESET_APP_PREFERENCES": { "TYPE": "TEXT", "VALUE": "Reset app preferences" }, "RESET_APPS": { "TYPE": "TEXT", "VALUE": "RESET APPS" }, "LANGUAGES_MENU": { "TYPE": "TEXT", "VALUE": "Languages" }, "LANGUAGES_MENU_IN_SELECTED_LANGUAGE": { "TYPE": "TEXT", "VALUE": "Idiomas" } }, "SECURITY": { "PATH": "Settings > Security", "OPTIONS": [ ], "TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_title", "PACKAGE": "com.android.car.settings.googlecarui.rro" }, "CHOOSE_LOCK_TYPE": { "TYPE": "TEXT", "VALUE": "Choose a lock type" }, "LOCK_TYPE_PASSWORD": { "TYPE": "TEXT", "VALUE": "Password" }, "LOCK_TYPE_PIN": { "TYPE": "TEXT", "VALUE": "PIN" }, "LOCK_TYPE_NONE": { "TYPE": "TEXT", "VALUE": "None" }, "CONTINUE_BUTTON": { "TYPE": "TEXT", "VALUE": "Continue" }, "CONFIRM_BUTTON": { "TYPE": "TEXT", "VALUE": "Confirm" }, "ENTER_PASSWORD": { "TYPE": "CLASS", "VALUE": "android.widget.EditText" }, "PIN_PAD": { "TYPE": "RESOURCE_ID", "VALUE": "pin_pad", "PACKAGE": "com.android.car.settings" }, "ENTER_PIN_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "key_enter", "PACKAGE": "com.android.car.settings" }, "REMOVE_BUTTON": { "TYPE": "TEXT", "VALUE": "Remove" } } }, "PHONE": { "APPLICATION_CONFIG": { "DIAL_PACKAGE": "com.android.car.dialer", "PHONE_ACTIVITY": "com.android.car.dialer/.ui.TelecomActivity", "OPEN_DIAL_PAD_COMMAND": "am start -a android.intent.action.DIAL" }, "IN_CALL_VIEW": { "DIALED_CONTACT_TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "user_profile_title", "PACKAGE": "com.android.car.dialer" }, "DIALED_CONTACT_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "user_profile_phone_number", "PACKAGE": "com.android.car.dialer" }, "END_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "end_call_button", "PACKAGE": "com.android.car.dialer" }, "MUTE_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "mute_button", "PACKAGE": "com.android.car.dialer" }, "SWITCH_TO_DIAL_PAD": { "TYPE": "RESOURCE_ID", "VALUE": "toggle_dialpad_button", "PACKAGE": "com.android.car.dialer" }, "CHANGE_VOICE_CHANNEL": { "TYPE": "RESOURCE_ID", "VALUE": "voice_channel_view", "PACKAGE": "com.android.car.dialer" }, "VOICE_CHANNEL_CAR": { "TYPE": "TEXT", "VALUE": "Car speakers" }, "VOICE_CHANNEL_PHONE": { "TYPE": "TEXT", "VALUE": "Phone" } }, "DIAL_PAD_VIEW": { "DIAL_PAD_MENU": { "TYPE": "TEXT", "VALUE": "Dial Pad" }, "DIAL_PAD_FRAGMENT": { "TYPE": "RESOURCE_ID", "VALUE": "dialpad_fragment", "PACKAGE": "com.android.car.dialer" }, "DIALED_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.dialer" }, "MAKE_CALL": { "TYPE": "RESOURCE_ID", "VALUE": "call_button", "PACKAGE": "com.android.car.dialer" }, "DELETE_NUMBER": { "TYPE": "RESOURCE_ID", "VALUE": "delete_button", "PACKAGE": "com.android.car.dialer" } }, "CONTACTS_VIEW": { "CONTACTS_MENU": { "TYPE": "TEXT", "VALUE": "Contacts" }, "CONTACT_INFO": { "TYPE": "RESOURCE_ID", "VALUE": "call_action_id", "PACKAGE": "com.android.car.dialer" }, "CONTACT_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.dialer" }, "CONTACT_DETAIL": { "TYPE": "RESOURCE_ID", "VALUE": "show_contact_detail_id", "PACKAGE": "com.android.car.dialer" }, "ADD_CONTACT_TO_FAVORITE": { "TYPE": "RESOURCE_ID", "VALUE": "contact_details_favorite_button", "PACKAGE": "com.android.car.dialer" }, "SEARCH_CONTACT": { "TYPE": "RESOURCE_ID", "VALUE": "menu_item_search", "PACKAGE": "com.android.car.dialer" }, "CONTACT_SEARCH_BAR": { "TYPE": "RESOURCE_ID", "VALUE": "car_ui_toolbar_search_bar", "PACKAGE": "com.android.car.dialer" }, "SEARCH_RESULT": { "TYPE": "RESOURCE_ID", "VALUE": "contact_name", "PACKAGE": "com.android.car.dialer" }, "CONTACT_SETTINGS": { "TYPE": "RESOURCE_ID", "VALUE": "menu_item_setting", "PACKAGE": "com.android.car.dialer" }, "CONTACT_ORDER": { "TYPE": "TEXT", "VALUE": "Contact order" }, "SORT_BY_FIRST_NAME": { "TYPE": "TEXT", "VALUE": "First name" }, "SORT_BY_LAST_NAME": { "TYPE": "TEXT", "VALUE": "Last Name" }, "CONTACT_TYPE_WORK": { "TYPE": "TEXT", "VALUE": "Work" }, "CONTACT_TYPE_MOBILE": { "TYPE": "TEXT", "VALUE": "Mobile" }, "CONTACT_TYPE_HOME": { "TYPE": "TEXT", "VALUE": "Home" } }, "CALL_HISTORY_VIEW": { "CALL_HISTORY_MENU": { "TYPE": "TEXT", "VALUE": "Recents" }, "CALL_HISTORY_INFO": { "TYPE": "RESOURCE_ID", "VALUE": "call_action_id", "PACKAGE": "com.android.car.dialer" } }, "FAVORITES_VIEW": { "FAVORITES_MENU": { "TYPE": "TEXT", "VALUE": "Favorites" } } }, "NOTIFICATIONS": { "APPLICATION_CONFIG": { "OPEN_NOTIFICATIONS_COMMAND": "service call statusbar 1" }, "EXPANDED_NOTIFICATIONS_SCREEN": { "NOTIFICATION_VIEW": { "TYPE": "RESOURCE_ID", "VALUE": "notification_view", "PACKAGE": "com.android.systemui" }, "CLEAR_ALL_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "clear_all_button", "PACKAGE": "com.android.systemui" }, "STATUS_BAR": { "TYPE": "RESOURCE_ID", "VALUE": "car_top_navigation_bar_container", "PACKAGE": "com.android.systemui" }, "APP_ICON": { "TYPE": "RESOURCE_ID", "VALUE": "app_icon", "PACKAGE": "com.android.systemui" }, "APP_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "header_text", "PACKAGE": "com.android.systemui" }, "NOTIFICATION_TITLE": { "TYPE": "RESOURCE_ID", "VALUE": "notification_body_title", "PACKAGE": "com.android.systemui" }, "NOTIFICATION_BODY": { "TYPE": "RESOURCE_ID", "VALUE": "notification_body_content", "PACKAGE": "com.android.systemui" }, "CARD_VIEW": { "TYPE": "RESOURCE_ID", "VALUE": "card_view", "PACKAGE": "com.android.systemui" } } }, "MEDIA_CENTER": { "APPLICATION_CONFIG": { "MEDIA_CENTER_PACKAGE": "com.android.car.media", "MEDIA_ACTIVITY": "com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService" }, "MEDIA_CENTER_SCREEN": { "PLAY_PAUSE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_pause_stop", "PACKAGE": "com.android.car.media" }, "NEXT_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_next", "PACKAGE": "com.android.car.media" }, "PREVIOUS_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_prev", "PACKAGE": "com.android.car.media" }, "SHUFFLE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "overflow_on", "PACKAGE": "com.android.car.media" }, "PLAY_QUEUE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_queue", "PACKAGE": "com.android.car.media" }, "MINIMIZED_MEDIA_CONTROLS": { "TYPE": "RESOURCE_ID", "VALUE": "minimized_playback_controls", "PACKAGE": "com.android.car.media" }, "TRACK_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.media" }, "TRACK_NAME_MINIMIZED_CONTROL": { "TYPE": "RESOURCE_ID", "VALUE": "minimized_control_bar_title", "PACKAGE": "com.android.car.media" }, "BACK_BUTTON": { "TYPE": "DESCRIPTION", "VALUE": "Back" } }, "MEDIA_CENTER_ON_HOME_SCREEN": { "PLAY_PAUSE_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "play_pause_stop", "PACKAGE": "com.android.car.carlauncher" }, "NEXT_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_next", "PACKAGE": "com.android.car.carlauncher" }, "PREVIOUS_BUTTON": { "TYPE": "RESOURCE_ID", "VALUE": "skip_prev", "PACKAGE": "com.android.car.carlauncher" }, "TRACK_NAME": { "TYPE": "RESOURCE_ID", "VALUE": "title", "PACKAGE": "com.android.car.carlauncher" } } } }
پیکربندیهای جایگزین دستگاه
نمونه کد زیر نمونهای از فایل پیکربندی JSON را نشان میدهد که در آن تنظیمات پیشفرض توسط تنظیمات روی DUT لغو میشوند. در این مثال:
تنظیمات اینترنت در دستگاههای مرجع با نام Network & internet و در دستگاه DUT با نام Connectivity مشخص شدهاند.
تنظیمات تاریخ و زمان برای دستگاههای مرجع در تنظیمات > تاریخ و زمان و برای دستگاه DUT در تنظیمات > سیستم > تاریخ و زمان موجود است.
// Default configuration file
{
....
"SECURITY_SETTINGS_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "fragment_container",
},
....
}
// JSON configuration file for non-reference device
{
....
"SECURITY_SETTINGS_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "car_ui_recycler_view"
},
....
}
وقتی فایل پیکربندی JSON آماده شد، همانطور که در بلوک کد زیر نشان داده شده است، در زمان اجرا ارائه میشود:
# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json
در این دستور:
DEVICE-SERIAL : شناسه سریال DUT. اگر فقط یک دستگاه به میزبان متصل باشد، این پارامتر لازم نیست.
PATH-TO-JSON-FILE : مسیر فایل JSON روی دستگاه میزبان.
قالب پیکربندی
پنج شیء سطح بالا در پیکربندی وجود دارد که کلیدها و مقادیر آنها به شرح زیر است:
| شیء | توضیحات |
|---|---|
PACKAGES | یک شیء که بسته اصلی برنامههای مختلف را توصیف میکند، که برای تعیین زمان اجرای برنامه در پیشزمینه استفاده میشود. |
ACTIONS | یک شیء که انواع اکشنها و پارامترهای مربوط به اکشنهای مختلف را نشان میدهد. برای مثال، آیا برای اسکرول کردن از دکمهها استفاده شود یا از ژست حرکتی. |
COMMANDS | شیءای که دستوراتی را مشخص میکند که اقدامات مختلفی را انجام میدهند. |
UI_ELEMENTS | یک شیء که برای ساخت UI Automator `BySelectors` استفاده میشود و عناصر UI را انتخاب میکند (در ادامه به تفصیل توضیح داده شده است). |
WORKFLOWS | توالی اقداماتی که وظایف سطح بالا را انجام میدهند (در زیر به تفصیل شرح داده شده است). |
عناصر رابط کاربری
هر عنصر رابط کاربری یک TYPE دارد که مشخص میکند UI Automator برای شناسایی عنصر (مانند شناسه منبع، متن و توضیحات) و مقادیر پیکربندی مرتبط با آن نوع، به دنبال چه چیزی میگردد. به طور کلی، هر زمان که یک helper با استفاده از این پیکربندی، عنصری را روی صفحه شناسایی کند، دقیقاً یک عنصر را دریافت میکند. اگر چندین عنصر با پیکربندی مطابقت داشته باشند، از یک عنصر دلخواه در تست استفاده میشود. بنابراین، پیکربندی (به طور کلی) باید به اندازه کافی خاص نوشته شود که در متن مربوطه به یک عنصر محدود شود.
متن
این سادهترین نوع عنصر رابط کاربری است. عنصر رابط کاربری با متن آن شناسایی میشود و نیاز به تطابق دقیق دارد.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
محتویات متن
همانند TEXT است، با این تفاوت که VALUE مشخص شده فقط باید در جایی از متن عنصر مورد نظر برای تطبیق ظاهر شود.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
شرح
عنصر را با ویژگی توصیف محتوای آن شناسایی کنید، که نیاز به تطابق دقیق دارد.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
شناسه منبع
عنصر را با شناسه منبع آن شناسایی کنید، و در صورت تمایل، مؤلفه بسته آن شناسه را نیز بررسی کنید. کلید PACKAGE اختیاری است؛ در صورت حذف، هر بستهای مطابقت خواهد داشت و فقط بخشی از شناسه که پس از :id/ قرار دارد، در نظر گرفته خواهد شد.
"APP_LIST_SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "apps_grid",
"PACKAGE": "com.android.car.carlauncher"
}
قابل کلیک، قابل پیمایش
عنصر را بر اساس اینکه آیا قابل کلیک یا پیمایش است (یا نیست) شناسایی کنید. اینها انواع عناصر بسیار گستردهای هستند و معمولاً فقط باید در یک MULTIPLE برای کمک به محدود کردن نوع عنصر دیگر استفاده شوند. کلید FLAG اختیاری است و به طور پیشفرض روی true تنظیم شده است.
"SAMPLE_ELEMENT": {
"TYPE": "CLICKABLE",
"FLAG": false
}
کلاس
عنصر را بر اساس کلاس آن شناسایی کنید.
"SECURITY_SETTINGS_ENTER_PASSWORD": {
"TYPE": "CLASS",
"VALUE": "android.widget.EditText"
}
HAS_ANCESTOR
عنصر را با جستجوی سلسله مراتب ویجت در اجداد آن شناسایی کنید. کلید ANCESTOR شیءای را در خود جای داده است که جد را شناسایی میکند. کلید DEPTH مشخص میکند که تا چه حد در سلسله مراتب جستجو شود. DEPTH اختیاری است و مقدار پیشفرض آن 1 است.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_ANCESTOR",
"DEPTH": 2,
"ANCESTOR": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
نسل دارد
عنصر را با نگاه کردن به پایین سلسله مراتب و فرزندانش شناسایی کنید. کلید DESCENDANT شیءای را در خود جای داده است که فرزند مورد نظر را مشخص میکند. کلید DEPTH مشخص میکند که تا چه حد در سلسله مراتب بالاتر جستجو شود. DEPTH اختیاری است و مقدار پیشفرض آن 1 است.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
چندگانه
عنصر را بر اساس چندین شرط همزمان شناسایی کنید، که همه آنها باید برقرار باشند.
"APP_INFO_SETTINGS_PERMISSION_MANAGER": {
"TYPE": "MULTIPLE",
"SPECIFIERS": [
{
"TYPE": "CLASS",
"VALUE": "android.widget.RelativeLayout"
},
{
"TYPE": "HAS_DESCENDANT",
"MAX_DEPTH": 2,
"DESCENDANT": {
"TYPE": "TEXT",
"VALUE": "Permission manager"
}
}
]
}
در این مثال، پیکربندی یک RelativeLayout را شناسایی میکند که دارای یک فرزند در عمق 2 است که متن Permission manager دارد.
گردشهای کاری
یک گردش کار، توالی از اقدامات مورد استفاده برای انجام یک کار خاص را نشان میدهد که ممکن است از نوع دستگاهی به نوع دیگر متفاوت باشد و نمایش آن در پیکربندی، انعطافپذیرتر از نمایش آن در کد است.
"WORKFLOWS": {
"OPEN_SOUND_SETTINGS_WORKFLOW": [
{
"NAME": "Go to Home",
"TYPE": "PRESS",
"CONFIG": {
"TEXT": "HOME"
}
},
{
"NAME": "Open Settings",
"TYPE": "COMMAND",
"CONFIG": {
"TEXT": "am start -a android.settings.SETTINGS"
}
},
{
"NAME": "Open Sound Settings",
"TYPE": "SCROLL_TO_FIND_AND_CLICK",
"CONFIG": {
"UI_ELEMENT": {
"TYPE": "TEXT",
"VALUE": "Sound"
}
},
"SCROLL_CONFIG": {
"SCROLL_ACTION": "USE_GESTURE",
"SCROLL_DIRECTION": "VERTICAL",
"SCROLL_ELEMENT": {
"TYPE": "RESOURCE_ID",
"VALUE": "car_ui_recycler_view"
}
}
}
]
}
هر گردش کار یک جفت کلید-مقدار است که در آن کلید، نام گردش کار و مقدار، آرایهای از اقدامات برای انجام است. هر اقدام دارای یک NAME ، یک TYPE ، (معمولاً) یک CONFIG و (گاهی اوقات) یک SWIPE_CONFIG یا SCROLL_CONFIG است. برای اکثر TYPEها، CONFIG یک شیء با کلید UI_ELEMENT است که مقدار آن همان شکل ورودی عنصر UI را دارد (به بالا مراجعه کنید). این TYPEها عبارتند از:
| مطبوعات فشار طولانی کلیک کلیک طولانی اگر وجود داشت، کلیک کنید | عنصر_رابط_کاربری_در_پیش_زمینه برای پیدا کردن و کلیک کردن اسکرول کنید برای یافتن و کلیک کردن، اسکرول کنید (اگر وجود داشت) برای پیدا کردن و کلیک کردن، بکشید (swipe_to_find_and_click) برای پیدا کردن و کلیک کردن، بکشید (یا: بکشید) اگر وجود داشت |
برای سایر TYPEها، جزئیات پیکربندی عبارتند از:
| شیء | توضیحات |
|---|---|
COMMAND | یک شیء با مقدار TEXT که حاوی دستوری برای اجرا است. |
HAS_PACKAGE_IN_FOREGROUND | یک شیء با مقدار TEXT که شامل بسته است. |
SWIPE | برای عملکرد SWIPE CONFIG key حذف کنید. این فقط SWIPE_CONFIG استفاده میکند. |
WAIT_MS | یک شیء با مقدار TEXT که شامل تعداد میلیثانیههایی است که باید منتظر بماند. |
اقدامات مربوط به پیمایش و کشیدن انگشت نیاز به پیکربندی اضافی دارند، به شرح زیر:
پیکربندی اسکرول
| شیء | توضیحات |
|---|---|
SCROLL_ACTION | یا USE_GESTURE یا USE_BUTTON |
SCROLL_DIRECTION | یا HORIZONTAL یا VERTICAL |
SCROLL_ELEMENT | یک شیء که نشان دهندهی کانتینر برای پیمایش است، با استفاده از همان فرم پیکربندی عنصر رابط کاربری (به بالا مراجعه کنید). |
SCROLL_FORWARD ، SCROLL_BACKWARD | دکمههای اسکرول به جلو و عقب (وقتی SCROLL_ACTION USE_BUTTON باشد، لازم است). |
SCROLL_MARGIN | اگر SCROLL_ACTION USE_GESTURE باشد، فاصله از لبه کانتینر برای شروع و توقف کشیدن که برای انجام پیمایش استفاده خواهد شد ( اختیاری، پیشفرض = ۱۰). |
SCROLL_WAIT_TIME | اگر SCROLL_ACTION برابر USE_GESTURE باشد، زمان انتظار بین حرکات اسکرول هنگام جستجوی یک شیء برای کلیک، بر حسب میلیثانیه است. ( اختیاری، پیشفرض = ۱). |
تنظیمات کشویی
| شیء | توضیحات |
|---|---|
SWIPE_DIRECTION | یا TOP_TO_BOTTOM ، BOTTOM_TO_TOP ، LEFT_TO_RIGHT ، یا RIGHT_TO_LEFT |
SWIPE_FRACTION | یکی از موارد زیر:
|
NUMBER_OF_STEPS | تعداد مراحلی که برای انجام عمل کشیدن انگشت باید طی شود. به segmentSteps مراجعه کنید. |
ساخت و اجرا
چارچوب Spectatio به طور خودکار به عنوان بخشی از APK آزمایشی ساخته میشود. برای ساخت APK آزمایشی، کدبیس AOSP باید روی ایستگاه کاری محلی قرار داشته باشد. پس از ساخت APK آزمایشی، کاربر باید APK را روی دستگاه نصب کرده و تست را اجرا کند.
نمونه کد زیر، ساخت، نصب و اجرای یک APK آزمایشی را نشان میدهد.
# Build Test APK make TEST-APK-NAME# Install Test APK adb -s DEVICE-SERIAL install -r PATH-FOR-BUILT-TEST-APK# Execute Test with the JSON file adb -s DEVICE-SERIAL shell am instrument -w -r -e debug false -e config-file-path /data/local/tmp/jsonFile.json -e class TEST-PACKAGE.TEST-CLASSNAME TEST-PACKAGE/androidx.test.runner.AndroidJUnitRunner
در این دستورات:
TEST-APK-NAME : نام برنامهای که قرار است آزمایش شود. برای مثال، TEST-APK-NAME را روی
AndroidAutomotiveSettingsTestsتنظیم کنید تا تنظیمات Wi-Fi مطابق با فایلAndroid.bpمشخص شده باشد. نام APK را میتوانید در فایلAndroid.bpمربوطه برای تست Automotive پیدا کنید.DEVICE-SERIAL : شناسه سریال DUT. اگر فقط یک دستگاه به میزبان متصل باشد، این پارامتر لازم نیست.
config-file-path: پارامتر اختیاری که فقط برای ارائه پیکربندیهای رابط کاربری غیر پیشفرض دستگاه، همانطور که در فایل پیکربندی JSON مشخص شده است، مورد نیاز است. در صورت عدم ارائه، چارچوب از مقادیر پیشفرض برای اجرای تستها استفاده میکند.PATH-FOR-BUILT-TEST-APK : مسیری که APK آزمایشی هنگام اجرای دستور
makeدر آن ساخته میشود.TEST-PACKAGE : نام بسته آزمایشی.
TEST-CLASSNAME : نام کلاس تست. برای مثال، برای تست تنظیمات وایفای ، پکیج تست
android.platform.testsو نام کلاس تستWifiSettingTestاست.
کتابخانه قطعه کد خودرو
کتابخانه قطعه کد خودرو (Automotive Snippet Library) مجموعهای از کتابخانههای تست اندروید برای پروژه متنباز اندروید (AOSP) است که برای تعامل با برنامهها و سرویسهای خودرو طراحی شده است. این کتابخانه از Spectatio با یک مکانیزم مناسب برای اجرای فراخوانیهای رویه از راه دور (RPC) از یک دستگاه میزبان (تست) به یک دستگاه مبتنی بر اندروید بهره میبرد.
شروع کنید
قبل از شروع، این بخشها را مرور کنید.
پیشنیازها
- پایتون ۳.x روی دستگاه میزبان نصب شده باشد.
- راهاندازی محیط AOSP به همراه ابزارهای ساخت لازم.
- یک دستگاه اندروید مخصوص خودرو (شبیهساز یا دستگاه فیزیکی) با دسترسی به adb.
گردآوری
برای کامپایل قطعه کدهای مختلف ارائه شده توسط کتابخانه Automotive Snippet، میتوانید از فایل android.bp ارائه شده استفاده کنید. برای کامپایل APK، از دستورات بخش قبل استفاده کنید.
استقرار
پس از کامپایل موفقیتآمیز کتابخانههای قطعه کد، فایلهای APK حاصل را با استفاده از دستور adb install که در بخش قبلی ذکر شد، روی دستگاه هدف مستقر کنید.
اجرای تستها
کتابخانههای قطعه کد، چندین متد RPC را برای تعامل با سیستم خودرو ارائه میدهند. این متدها را میتوان از طریق چارچوب Mobly از دستگاه میزبان فراخوانی کرد. با فرض اینکه محیط تست Mobly را تنظیم کردهاید، میتوانید از اسکریپت snippet_shell.py برای باز کردن یک پوسته پایتون تعاملی استفاده کنید، جایی که میتوانید متدهای RPC را به صورت دستی روی دستگاه فراخوانی کنید. مثال فراخوانی:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
به جای <serial> شماره سریال دستگاه را قرار دهید، که در صورت اتصال چندین دستگاه، میتوانید آن را با adb devices دریافت کنید.
کتابخانههای موجود
کتابخانه قطعه کد خودرو شامل کتابخانهها و کمککنندههای قطعه کد زیر است:
AutomotiveSnippet: رابطهای برنامهنویسی کاربردی (API) مربوط به عملیات خودرو، مانند شمارهگیری، کنترل صدا، کلیدهای سختافزاری خودرو و تعامل با مرکز رسانه را ارائه میدهد.
PhoneSnippet: رابطهای برنامهنویسی کاربردی (API) مرتبط با تلفن، از جمله مدیریت تماس، مرور مخاطبین و عملیات پیامک را ارائه میدهد.
قطعه کد Automotive و PhoneSnippet منطق مشترکی دارند. به طور خاص، میتوانید به فراخوانیهای RCP مربوط به بلوتوث برای جفت کردن یک دستگاه خودرو و تلفن دسترسی پیدا کنید. این bt_discovery_test نحوه انجام این کار را نشان میدهد.
- TEST-CLASSNAME : نام کلاس تست. برای مثال، برای تست تنظیمات وایفای ، پکیج تست
android.platform.testsو نام کلاس تستWifiSettingTestاست.