Test Device Configuration
Use ADB to launch specific app pages:
adb shell start -n [package_name]/[activity_name]
Creating a new session starts a fresh testing environment.
Download applications to your computer using official app stores like Baidu App Store.
Install applications using:
adb install -r app_name.apk
Alternatively, drag and drop the APK file directly into the emulator.
To install applications on multiple emulators or devices simultaneously:
Uninstall applications with:
adb uninstall [package_name]
Application File Management
Installation Methods
- Download from official app stores (Google Play, App Store)
- Download from web platforms (like Baidu App Store) and transfer to device
- Install via command line:
adb install app_name.apk
Uninstallation Methods
- Uninstall directly from the emulator by long-pressing the app and dragging to delete
- Use command line:
adb uninstall package_name
Example for WeChat Work:
adb uninstall com.tencent.wework
Appium Desktop Setup
Click "Start Server" to initiate the Appium service.
Configure Desired Capabilities as follows:
{
"platformName": "android",
"deviceName": "emulator-5554",
"appPackage": "com.tencent.wework",
"appActivity": ".launch.LaunchSplashActivity",
"autoGrantPermissions": "true",
"noReset": "true"
}
Essential ADB Commands
adb devices- List connected devicesadb logcat | grep -i Displayed- Filter app activity transitionsadb shell am start -n [package]/[activity]- Launch specific activity
Example activities for WeChat Work:
com.tencent.wework/.launch.LaunchSplashActivity
com.tencent.wework/.launch.WwMainActivity
Note: The splash screen and main activity are different. While theoretically any page can be directly accessed, developers often restrict this to simulate real user scenarios.
Port Analysis in Mobile Testing
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
0.0.0.0 is equivalent to localhost and should match the port in your script. Port 4723 is used for establishing communication between server and client.
UIAutomator2 uses a server APK on the device that typically operates on port 8200 to receive requests from the server.
Port 5037 is used for ADB communication between Android devices and PC (Android Debug Bridge).
Ports in the 8000+ range are typiclaly used for Chromedriver communication with webviews.
Element Positioning Strategies
Appium Desktop allows saving previous configurations for reuse.
When multiple elements share the same identifier, use sibling nodes or other attributes to differentiate. Both By.XPATH and MobileBy can be employed for ID or xpath searches.
For list pages requiring scrolling (like adding contacts in WeChat Work with many entries), use scrollable views:
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("添加成员").instance(0))'
Element positioning principles:
- Always use IDs when available
- Avoid excessive explicit waits (though 1-2 seconds can be helpful during debugging)
For example, to find a name input field, searching by name is more reliable than by placeholder text. Use contains() for partial text matches:
"//*[contains(@text,'姓名')]/..//*[@resource-id='com.tencent.wework:id/ase']"
The double dots (..) represent the parent node, allowing you to find a child with a specific ID.
The same approach can be used for other elements like gander selection.
For toast notifications (brief system messages), locate them by class attribute or XPath:
toast = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert '添加成功' in toast
When multiple elements share the same text attribute, the first matching element is located by default.
Current Activity Identification
Method 1: Use Appium Desktop to identify the current activity.
Method 2: Programmatically get the current activity and assert it matches expectations.
Debugging Approaches
Identify error locations by line numbers and add print statements. Compare expected and actual values to pinpoint discrepancies. If issues persist, examine server-side error messages.
Clicking on error lines in your IDE can directly navigate to the problematic code.
Test Case Parameterization
Parameterization normally restarts the app for each parameter set. To avoid this, use class methods with teardown methods that return to the previous screen.
from time import sleep
from appium import webdriver
import yaml
import pytest
from appium.webdriver.common.mobileby import MobileBy
class TestContactAdd():
def setup_class(self):
desired_caps = {}
desired_caps['platformName'] = 'android'
desired_caps['platformVersion'] = '6.0'
desired_caps['deviceName'] = 'emulator-5554'
desired_caps['appPackage'] = 'com.tencent.wework'
desired_caps['appActivity'] = '.launch.LaunchSplashActivity'
desired_caps['noReset'] = 'true'
desired_caps['dontStopAppOnReset'] = 'true'
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
self.driver.implicitly_wait(5)
def setup(self):
pass
def teardown(self):
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/gpp').click()
def teardown_class(self):
self.driver.quit()
@pytest.mark.parametrize("mobile,name,gender", [('17801153312', 'TestUser12', 'Male'), ('17801153311', 'TestUser11', 'Female')])
def test_add_member(self, mobile, name, gender):
# Navigate to contacts
contacts = self.driver.find_element_by_xpath("//*[@text='Contacts']")
contacts.click()
# Scroll to and click "Add Member"
add_member = self.driver.find_element_by_android_uiautomator(
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("Add Member").instance(0))')
add_member.click()
# Click manual add button
self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/c56').click()
sleep(2)
# Enter name
name_field = self.driver.find_element(MobileBy.XPATH,
"//*[contains(@text,'Name')]/..//*[@resource-id='com.tencent.wework:id/ase']")
name_field.send_keys(name)
# Enter mobile number
mobile_field = self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/emh')
mobile_field.send_keys(mobile)
# Select gender
gender_button = self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/ate')
gender_button.click()
# Choose specific gender
self.driver.find_element(MobileBy.XPATH, f"//*[@text='{gender}']").click()
# Save the new contact
save_button = self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/gq7')
save_button.click()
sleep(2)
# Verify success toast
toast = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert '添加成功' in toast
Alternatively, use fixtures to avoid code redundancy:
@pytest.fixture
def app_setup():
desired_caps = {
'platformName': 'android',
'platformVersion': '6.0',
'deviceName': 'emulator-5554',
'appPackage': 'com.tencent.wework',
'appActivity': '.launch.LaunchSplashActivity',
'noReset': 'true',
'dontStopAppOnReset': 'true'
}
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
driver.implicitly_wait(5)
yield driver
driver.quit()