import time
import os
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pandas as pd
# 存储测试日志的列表
test_results = []
def log_result(action, element_desc, status, message=""):
"""记录每一步的操作结果"""
test_results.append({
"Action": action,
"Element": element_desc,
"Status": status,
"Message": message,
"Timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
})
# Appium 配置
desired_caps = {
"platformName": "Android",
"deviceName": "emulator-5554", # 使用 adb devices 查看设备名
"appPackage": "com.example.yourapp", # 替换为实际包名
"appActivity": "com.example.yourapp.MainActivity", # 替换为主 Activity
"noReset": False,
"autoAcceptAlerts": True,
"automationName": "UiAutomator2"
}
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
wait = WebDriverWait(driver, 10)
action = TouchAction(driver)
try:
# === 第一阶段:处理用户协议页面 ===
log_result("Start", "App Launch", "Success", "APP launched successfully")
# 假设协议页面存在一个 ScrollView 或可滑动区域
scroll_container = (AppiumBy.CLASS_NAME, "android.widget.ScrollView")
agree_button = (AppiumBy.ID, "com.example.yourapp:id/btn_agree") # “我同意”按钮 ID
disagree_button = (AppiumBy.ID, "com.example.yourapp:id/btn_disagree") # “我不同意”
# 等待滑动容器出现
try:
wait.until(EC.presence_of_element_located(scroll_container))
log_result("Wait", "Scroll View Loaded", "Success", "Located scrollable area")
except:
log_result("Wait", "Scroll View", "Fail", "No scrollable view found")
raise
# 滑动到底部(多次滑动直到按钮可见)
for _ in range(10):
try:
if driver.find_elements(*agree_button):
log_result("Scroll", "Find 'I Agree' Button", "Success", "Button appeared after scrolling")
break
except:
pass
# 执行一次向上滑动(模拟用户阅读协议)
size = driver.get_window_size()
start_x = size['width'] // 2
start_y = int(size['height'] * 0.8)
end_y = int(size['height'] * 0.2)
driver.swipe(start_x, start_y, start_x, end_y, 1000)
time.sleep(1)
else:
log_result("Scroll", "'I Agree' Button", "Fail", "Failed to reach agreement buttons")
raise Exception("Could not find 'I Agree' button after scrolling")
# 点击“我同意”
try:
btn_agree = wait.until(EC.element_to_be_clickable(agree_button))
btn_agree.click()
log_result("Click", "I Agree Button", "Success", "Proceeded to next screen")
except Exception as e:
log_result("Click", "I Agree Button", "Fail", str(e))
raise
time.sleep(2)
# === 第二阶段:选择机器设备 ===
device_item = (AppiumBy.ID, "com.example.yourapp:id/device_item") # 设备项示例 ID
try:
first_device = wait.until(EC.element_to_be_clickable(device_item))
first_device.click()
log_result("Select", "First Machine", "Success", "Entered main screen")
except Exception as e:
log_result("Select", "Machine", "Fail", str(e))
raise
time.sleep(3)
# === 第三阶段:遍历底部导航栏 ===
# 假设底部有 4 个 Tab,ID 分别为 tab_home, tab_order, tab_mine 等
tab_ids = [
"com.example.yourapp:id/tab_home",
"com.example.yourapp:id/tab_order",
"com.example.yourapp:id/tab_message",
"com.example.yourapp:id/tab_mine"
]
for tab_id in tab_ids:
try:
tab = wait.until(EC.element_to_be_clickable((AppiumBy.ID, tab_id)))
tab_name = tab_id.split(":id/")[-1].capitalize()
tab.click()
time.sleep(2) # 等待页面加载
log_result("Navigate", f"Tab - {tab_name}", "Success", f"Switched to {tab_name} page")
except Exception as e:
log_result("Navigate", f"Tab - {tab_id}", "Fail", str(e))
continue # 继续尝试下一个 tab
# === 第四阶段:在当前页面抓取所有可交互元素 ===
all_elements = driver.find_elements(AppiumBy.XPATH, "//*")
clickable_elements = [e for e in all_elements if e.get_attribute("clickable") == "true"]
editable_elements = [e for e in all_elements if e.get_attribute("editable") == "true"]
# 去重(避免同一个元素既可点击又可编辑)
processed_ids = set()
for idx, elem in enumerate(clickable_elements):
elem_id = id(elem)
if elem_id in processed_ids:
continue
try:
# 尝试滚动到元素可见
driver.execute_script("arguments[0].scrollIntoView(true);", elem)
time.sleep(0.5)
elem.click()
desc = f"Clickable Element #{idx}"
attr_text = elem.get_attribute("text") or elem.get_attribute("content-desc") or "No text"
log_result("Click", desc, "Success", f"Text: {attr_text}")
processed_ids.add(elem_id)
time.sleep(1)
except Exception as e:
log_result("Click", f"Element #{idx}", "Fail", str(e))
for idx, elem in enumerate(editable_elements):
elem_id = id(elem)
if elem_id in processed_ids:
continue
try:
driver.execute_script("arguments[0].scrollIntoView(true);", elem)
time.sleep(0.5)
elem.clear() # 清空输入框
elem.send_keys("AutoTest Input")
desc = f"Editable Element #{idx}"
attr_text = elem.get_attribute("text") or elem.get_attribute("hint") or "Input field"
log_result("Input", desc, "Success", f"Typed into: {attr_text}")
processed_ids.add(elem_id)
time.sleep(1)
except Exception as e:
log_result("Input", f"Element #{idx}", "Fail", str(e))
finally:
# === 第五阶段:生成 Excel 报告 ===
df = pd.DataFrame(test_results)
output_file = "app_automation_test_report.xlsx"
df.to_excel(output_file, index=False)
print(f"[INFO] 测试完成,报告已保存至: {os.path.abspath(output_file)}")
# 关闭驱动
driver.quit()
将desired_caps替换为options