Spectatio는 실제 기기와 가상 기기에서 Android Automotive OS(AAOS)를 테스트하려고 개발된 오픈소스 테스트 프레임워크입니다. Spectatio는 자동차 기기에서 앱을 테스트하기 위한 API를 제공하며 AAOS 및 앱의 기능과 성능을 확인하는 데 사용되는 확장 가능하고 확장 가능한 솔루션입니다.
대략적인 구성
Spectatio 프레임워크는 다양한 AAOS UI 구현에 맞게 조정 가능하고 확장 가능합니다. 기기 하드웨어, 에뮬레이터, 가상화된 환경에서 AAOS의 기능과 성능을 테스트하는 데 사용됩니다.
다음 그림은 Spectatio 프레임워크의 대략적인 구성을 설명합니다.
그림 1. Spectatio 프레임워크의 대략적인 구성
UI Automator에 기반하여 빌드된 Spectatio 프레임워크는 AAOS에서 사용자 및 시스템 앱과 상호작용하는 UI 테스트를 빌드하는 API 모음을 제공합니다. Automotive 테스트는 Spectatio 프레임워크에서 제공하는 API를 사용하여 실행되므로 테스트 대상 기기 (DUT)와는 별개이며 지원되는 경우 다양한 기기를 테스트하도록 확장 가능합니다.
그림 1은 Spectatio 프레임워크가 앱별 인터페이스와 도우미를 사용하여 다이얼러, Medicenter, 설정과 같은 참조 앱을 바탕으로 모듈화되므로 새 앱에 맞도록 쉽게 확장 가능함을 보여줍니다. Spectatio 프레임워크는 공통 표준 및 유틸리티 도우미 클래스를 재사용합니다. 표준 도우미 클래스는 모든 앱 도우미 함수의 상위 클래스이며 기기별 또는 앱 전반에 사용할 수 있는 표준 함수를 제공합니다. 유틸리티 도우미 클래스는 기기에서 파일 읽기 또는 쓰기와 같은 유틸리티를 제공합니다.
아키텍처
UI 테스트를 빌드하는 API 모음을 제공하기 위해 Spectatio 프레임워크는 앱별 인터페이스 및 도우미를 구현하면서 기존 표준 도우미 클래스를 확장하고 유틸리티 도우미 클래스를 가져옵니다.
그림 2는 Spectatio 프레임워크의 대략적인 아키텍처와 앱 테스트를 위한 API 구현과 관련된 모든 항목을 보여줍니다.
그림 2. Spectatio 프레임워크의 대략적인 아키텍처
앱 도우미 인터페이스는 앱 도우미 구현을 위한 청사진을 제공합니다. 앱 테스트에 필요한 다양한 도우미 함수로 구성됩니다. 각 앱에는 IAutoSettingHelper
및 IAutoDialHelper
와 같은 자체 인터페이스가 있습니다.
자세한 내용과 인터페이스 함수 목록은 AOSP의 앱 도우미 인터페이스 함수를 참고하세요.
표준 도우미 클래스는 기기 설정에 필요하지만 앱과는 관련이 없는 표준 속성과 함수로 구성됩니다(예: pressHome
, scroll
). 표준 도우미 클래스는 AbstractAutoStandardAppHelper.java
에 정의되어 있습니다.
유틸리티 도우미 클래스는 Spectatio 프레임워크에 의해 사용됩니다. 예를 들어 AutoJsonUtility.java
는 지정된 기기 JSON 구성 파일을 로드하고 런타임 시 프레임워크 구성을 업데이트하는 유틸리티 클래스입니다.
앱 도우미 구현 모듈은 Spectatio 프레임워크의 핵심입니다. 여기에는 자동차 기기에서 앱을 테스트하는 데 필요한 앱 도우미 인터페이스에 정의된 도우미 함수의 구현이 포함됩니다. 각 앱에는 SettingHelperImpl
및 DialHelperImpl
와 같은 자체 구현이 있고 이는 Automotive의 앱 테스트에서 사용됩니다. 자세한 내용과 구현 목록은 AOSP의 앱 도우미 구현 함수를 참고하세요.
Automotive 테스트는 앱 도우미 구현 함수를 사용하여 앱과 관련된 다양한 작업을 테스트합니다. HelperAccessor
클래스를 사용하면 앱 도우미 구현 함수에 액세스할 수 있습니다.
다음 코드는 샘플 Automotive 테스트의 설정, 정리, 실행을 보여줍니다.
@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 프레임워크는 기기 UI와는 별개이므로 다양한 UI와 하드웨어를 사용하는 기기 테스트를 위해 확장 가능합니다. Spectatio에서는 확장성을 실현하기 위해 참조 기기에 기반한 기본 기기 설정을 사용하고 기본이 아닌 기기 구성을 지원하기 위해 런타임 시 JSON 구성 파일을 사용해 원하는 UI 변경사항을 기기에 설정합니다. JSON 구성 파일은 TEXT
, DESCRIPTION
, RESOURCE_ID
와 같은 UI 요소와 path
설정을 지원하며 DUT의 UI 변경사항에 관한 정보만 포함해야 합니다. 나머지 UI 요소는 프레임워크에 제공된 기본 구성 값을 사용합니다.
기본 기기 설정
다음 샘플 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" } } } }
대체 기기 설정
다음 코드 샘플은 기본 설정이 DUT의 설정으로 재정의된 JSON 구성 파일의 예를 보여줍니다. 이 예는 다음과 같습니다.
인터넷 설정은 참조 기기에서는 네트워크 및 인터넷으로, DUT에서는 연결로 지정됩니다.
날짜 및 시간 설정은 참조 기기의 경우 설정 > 날짜 및 시간, 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의 일련번호 ID입니다. 이 매개변수는 기기 한 대만 호스트에 연결된 경우 필요하지 않습니다.
PATH-TO-JSON-FILE: 호스트 머신의 JSON 파일 경로입니다.
구성 형식
구성에는 다음과 같은 키와 값이 포함된 5개의 최상위 객체가 있습니다.
객체 | 설명 |
---|---|
PACKAGES |
다양한 앱의 기본 패키지를 설명하는 객체로, 앱이 포그라운드에 있는 시점을 결정하는 데 사용됩니다. |
ACTIONS |
다양한 작업의 작업 유형 및 매개변수를 나타내는 객체입니다. 예를 들어 스크롤하는 데 버튼을 사용할지 동작을 사용할지 여부입니다. |
COMMANDS |
다양한 작업을 실행하는 명령어를 지정하는 객체입니다. |
UI_ELEMENTS |
UI 요소를 선택하는 UI Automator `BySelectors` 를 생성하는 데 사용되는 객체입니다 (아래에 자세히 설명). |
WORKFLOWS |
상위 수준의 작업을 실행하는 작업 시퀀스입니다 (아래에 자세히 설명됨). |
UI 요소
각 UI 요소에는 UI Automator가 요소를 식별하기 위해 확인할 항목 (예: 리소스 ID, 텍스트, 설명)과 해당 유형과 연결된 구성 값을 지정하는 TYPE
가 있습니다. 일반적으로 도우미는 이 구성을 사용하여 화면에서 요소를 식별할 때마다 정확히 하나의 요소를 가져옵니다. 구성과 일치하는 요소가 여러 개인 경우 테스트에 임의의 요소가 사용됩니다. 따라서 구성은 일반적으로 관련 맥락에서 하나의 요소로 좁혀질 만큼 구체적으로 작성되어야 합니다.
텍스트
가장 간단한 UI 요소 유형입니다. UI 요소는 텍스트로 식별되며 정확한 일치가 필요합니다.
"CALL_HISTORY_MENU": {
"TYPE": "TEXT",
"VALUE": "Recents"
}
TEXT_CONTAINS
지정된 VALUE
가 일치할 요소의 텍스트 어딘가에만 표시되어야 한다는 점을 제외하고는 TEXT
와 동일합니다.
"PRIVACY_CALENDAR": {
"TYPE": "TEXT_CONTAINS",
"VALUE": "Calendar"
}
설명
콘텐츠 설명 속성으로 요소를 식별합니다. 정확한 일치가 필요합니다.
"APP_GRID_SCROLL_BACKWARD_BUTTON": {
"TYPE": "DESCRIPTION",
"VALUE": "Scroll up"
}
RESOURCE_ID
리소스 ID로 요소를 식별하고 원하는 경우 해당 ID의 패키지 구성요소도 확인합니다. PACKAGE
키는 선택사항입니다. 생략하면 모든 패키지가 일치하며 :id/
다음의 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
}
CLASS
클래스를 기반으로 요소를 식별합니다.
"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"
}
}
HAS_DESCENDANT
계층 구조에서 하위 요소를 찾아 요소를 식별합니다. DESCENDANT
키에는 찾을 하위 요소를 지정하는 객체가 포함됩니다. DEPTH
키는 계층 구조에서 얼마나 위로 볼지 지정합니다. DEPTH
는 선택사항이며 기본값은 1
입니다.
"SAMPLE_ELEMENT": {
"TYPE": "HAS_DESCENDANT",
"DEPTH": 2,
"DESCENDANT": {
"TYPE": "CLASS",
"VALUE": "android.view.ViewGroup"
}
}
MULTIPLE
모두 충족되어야 하는 여러 동시 조건을 기준으로 요소를 식별합니다.
"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"
}
}
]
}
이 예에서 구성은 2
깊이에 Permission manager
텍스트가 있는 하위 요소가 있는 RelativeLayout
를 식별합니다.
워크플로
워크플로는 특정 작업을 실행하는 데 사용되는 일련의 작업을 나타냅니다. 워크플로는 기기 유형에 따라 충분히 다를 수 있으며 코드보다 구성을 통해 표현하기에 더 유연합니다.
"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 요소 항목과 동일한 형식을 취하는 UI_ELEMENT
키가 있는 객체입니다 (위 참고). 이러한 TYPE은 다음과 같습니다.
PRESS LONG_PRESS CLICK LONG_CLICK CLICK_IF_EXIST |
HAS_UI_ELEMENT_IN_FOREGROUND SCROLL_TO_FIND_AND_클릭 SCROLL_TO_FIND_AND_클릭_IF_EXIST 스와이프_TO_FIND_AND_클릭 스와이프로_FIND_AND_클릭_IF_EXIST |
다른 TYPE의 경우 구성 세부정보는 다음과 같습니다.
객체 | 설명 |
---|---|
COMMAND |
실행할 명령어가 포함된 TEXT 값이 있는 객체입니다. |
HAS_PACKAGE_IN_FOREGROUND |
패키지가 포함된 TEXT 값이 있는 객체입니다. |
SWIPE |
SWIPE 작업의 경우 CONFIG key 를 생략합니다. 이 방법은 SWIPE_CONFIG 만 사용합니다. |
WAIT_MS |
대기할 밀리초 수를 포함하는 TEXT 값이 있는 객체입니다. |
스크롤 및 스와이프 관련 작업에는 다음과 같이 추가 구성이 필요합니다.
SCROLL_CONFIG
객체 | 설명 |
---|---|
SCROLL_ACTION |
USE_GESTURE 또는 USE_BUTTON |
SCROLL_DIRECTION |
HORIZONTAL 또는 VERTICAL |
SCROLL_ELEMENT |
UI 요소 구성과 동일한 형식을 사용하여 스크롤할 컨테이너를 나타내는 객체입니다 (위 참조). |
SCROLL_BACKWARD SCROLL_FORWARD |
앞으로 및 뒤로 스크롤 버튼 (SCROLL_ACTION 이 USE_BUTTON 인 경우 필요) |
SCROLL_MARGIN |
SCROLL_ACTION 이 USE_GESTURE 이면 스크롤을 실행하는 데 사용되는 드래그를 시작하고 중지하는 컨테이너 가장자리의 거리입니다 (선택사항, 기본값 = 10). |
SCROLL_WAIT_TIME |
SCROLL_ACTION 가 USE_GESTURE 이면 클릭할 객체를 검색할 때 스크롤 동작 간에 대기할 시간(밀리초)입니다.
(선택사항, 기본값 = 1) |
SWIPE_CONFIG
객체 | 설명 |
---|---|
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: 테스트할 앱의 이름입니다. 예를 들어
Android.bp
파일에 지정된 대로 TEST-APK-NAME을AndroidAutomotiveSettingsTests
로 설정하여 Wi-Fi 설정을 테스트합니다. APK의 이름은 자동차 테스트의 각Android.bp
파일에서 확인할 수 있습니다.DEVICE-SERIAL: DUT의 일련번호 ID입니다. 이 매개변수는 기기 한 대만 호스트에 연결된 경우 필요하지 않습니다.
config-file-path
: JSON 구성 파일에 지정된 대로 기본이 아닌 기기 UI 구성을 제공하는 목적으로만 필요한 선택적 매개변수입니다. 제공되지 않으면 프레임워크는 테스트 실행을 위해 기본값을 사용합니다.PATH-FOR-BUILT-TEST-APK:
make
명령어가 실행될 때 테스트 APK가 빌드되는 경로입니다.TEST-PACKAGE: 테스트 패키지의 이름입니다.
TEST-CLASSNAME: 테스트 클래스의 이름입니다. 예를 들어 Wi-Fi 설정 테스트의 경우 테스트 패키지는
android.platform.tests
이고 테스트 클래스 이름은WifiSettingTest
입니다.
Automotive 스니펫 라이브러리
Automotive Snippet Library는 Automotive 앱 및 서비스와 상호작용하도록 설계된 Android 오픈소스 프로젝트 (AOSP)용 Android 테스트 라이브러리 모음입니다. 호스트 (테스트) 머신에서 Android 지원 기기로 원격 프로시저 호출 (RPC)을 실행하는 편리한 메커니즘으로 Spectatio를 활용합니다.
시작하기
시작하기 전에 다음 섹션을 검토하세요.
기본 요건
- 호스트 머신에 Python 3.x가 설치되어 있습니다.
- 필요한 빌드 도구가 포함된 AOSP 환경 설정
- adb 액세스가 가능한 Android Automotive 기기 (에뮬레이터 또는 실제 기기)
컴파일
Automotive 스니펫 라이브러리에서 제공하는 다양한 스니펫을 컴파일하려면 제공된 android.bp
파일을 사용하면 됩니다. 이전 섹션의 명령어에 따라 APK를 컴파일합니다.
배포
스니펫 라이브러리를 성공적으로 컴파일한 후 결과 APK를 이전 섹션에서 언급한 adb install
명령어를 사용하여 대상 기기에 배포합니다.
테스트 실행
스니펫 라이브러리는 자동차 시스템과 상호작용하는 여러 RPC 메서드를 노출합니다. 이러한 메서드는 호스트 머신에서 Mobly 프레임워크를 통해 호출할 수 있습니다. Mobly 테스트 환경이 설정되어 있다고 가정하면 snippet_shell.py
스크립트를 사용하여 대화형 Python 셸을 열 수 있습니다. 여기에서 기기에서 RPC 메서드를 수동으로 호출할 수 있습니다. 호출 예시:
python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>
<serial>
를 기기 일련번호로 바꿉니다. 여러 기기가 연결된 경우 adb devices를 사용하여 가져올 수 있습니다.
포함된 라이브러리
Automotive 스니펫 라이브러리에는 다음과 같은 스니펫 라이브러리와 도우미가 포함되어 있습니다.
AutomotiveSnippet: 전화 걸기, 볼륨 제어, 차량 하드 키, 미디어 센터 상호작용과 같은 차량 작업과 관련된 API를 제공합니다.
Phonesnippet: 통화 처리, 연락처 탐색, SMS 작업 등 전화 통신 관련 API를 제공합니다.
Automotive 스니펫과 PhoneSnippet은 몇 가지 공통적인 로직을 공유합니다.
특히 블루투스 관련 RCP 호출을 침입하여 자동차 기기와 휴대전화 기기를 페어링할 수 있습니다. 이 bt_discovery_test
를 참고하세요.
- TEST-CLASSNAME: 테스트 클래스의 이름입니다. 예를 들어 Wi-Fi 설정 테스트의 경우 테스트 패키지는
android.platform.tests
이며 테스트 클래스 이름은WifiSettingTest
입니다.