移动端Web自动化测试:汉堡菜单打开断言失败求助
移动端Web自动化测试:汉堡菜单打开断言失败求助
大家好,我现在在做Android移动端Web的自动化测试,用Appium + Pytest框架测试Chrome浏览器里的汉堡菜单功能。执行测试时,模拟器能正常打开Chrome并加载目标URL,但尝试打开汉堡菜单后,断言一直失败,提示AssertionError: Burger is not open. class='burger',想请各位帮忙排查下问题~
问题复现步骤
- 启动Android模拟器(Pixel 8,Android 16.0)
- 启动Appium服务
- 运行Pytest测试用例
- 模拟器打开Chrome加载目标URL后,执行汉堡菜单打开操作,最终断言失败
环境与执行命令
启动命令
- 启动模拟器:
emulator -avd Pixel - 启动Appium:
appium --allow-insecure="*:chromedriver_autodownload" - 运行测试:
pytest tests/test_burger_menu.py::test_open_burger_menu --no-header --no-summary -q
相关代码片段
conftest.py(配置文件)
import pytest from appium import webdriver from appium.options.android import UiAutomator2Options def pytest_addoption(parser): parser.addoption("--appium-url", action="store", default="http://127.0.0.1:4723") parser.addoption("--udid", action="store", default="emulator-5554") parser.addoption( "--base-url", action="store", default="https://www.example.com", ) @pytest.fixture(scope="session") def base_url(request) -> str: return request.config.getoption("--base-url") @pytest.fixture def driver(request): appium_url = request.config.getoption("--appium-url") udid = request.config.getoption("--udid") options = UiAutomator2Options() options.platform_name = "Android" options.automation_name = "UiAutomator2" options.udid = udid options.browser_name = "Chrome" options.new_command_timeout = 120 options.set_capability("appium:uiautomator2ServerLaunchTimeout", 120000) options.set_capability("appium:uiautomator2ServerInstallTimeout", 120000) options.set_capability("appium:uiautomator2ServerStartupTimeout", 120000) options.set_capability("appium:skipLogcatCapture", True) options.set_capability("appium:clearSystemFiles", True) options.set_capability("appium:ignoreHiddenApiPolicyError", True) # Important for mobile Chrome: don't wait for full page load (reduces hangs/crashes) options.set_capability("pageLoadStrategy", "none") # Disable first-run/Welcome screen in Chrome options.set_capability("appium:chromeOptions", {"args": ["--disable-fre", "--no-first-run"]}) drv = webdriver.Remote(appium_url, options=options) try: yield drv finally: drv.quit()
pages/home_page.py(注:当前代码存在粘贴错误,重复了conftest配置,实际应为页面对象类)
import pytest from appium import webdriver from appium.options.android import UiAutomator2Options def pytest_addoption(parser): parser.addoption("--appium-url", action="store", default="http://127.0.0.1:4723") parser.addoption("--udid", action="store", default="emulator-5554") parser.addoption( "--base-url", action="store", default="https://www.particleformen.com/?store_switch=en", ) @pytest.fixture(scope="session") def base_url(request) -> str: return request.config.getoption("--base-url") @pytest.fixture def driver(request): appium_url = request.config.getoption("--appium-url") udid = request.config.getoption("--udid") options = UiAutomator2Options() options.platform_name = "Android" options.automation_name = "UiAutomator2" options.udid = udid options.browser_name = "Chrome" options.new_command_timeout = 120 options.set_capability("appium:uiautomator2ServerLaunchTimeout", 120000) options.set_capability("appium:uiautomator2ServerInstallTimeout", 120000) options.set_capability("appium:uiautomator2ServerStartupTimeout", 120000) options.set_capability("appium:skipLogcatCapture", True) options.set_capability("appium:clearSystemFiles", True) options.set_capability("appium:ignoreHiddenApiPolicyError", True) # Important for mobile Chrome: don't wait for full page load (reduces hangs/crashes) options.set_capability("pageLoadStrategy", "none") # Disable first-run/Welcome screen in Chrome options.set_capability("appium:chromeOptions", {"args": ["--disable-fre", "--no-first-run"]}) drv = webdriver.Remote(appium_url, options=options) try: yield drv finally: drv.quit()
tests/test_burger_menu.py(测试用例)
import pytest import allure from pages.home_page import HomePage @allure.epic("Mobile Web Tests") @allure.feature("Home Page") @pytest.mark.smoke @allure.story("Burger menu functionality") def test_open_burger_menu(driver, base_url): with allure.step("Open home page"): HomePage(driver).open(base_url).assert_loaded() with allure.step("Open burger menu"): HomePage(driver).open_menu() with allure.step("Verify menu is opened"): HomePage(driver).assert_menu_opened()
我的疑惑与当前排查点
- 发现
pages/home_page.py的代码错误重复了conftest的配置,实际应该是封装元素操作的页面对象类,这大概率是问题根源之一 - 页面加载策略设置为
none,会不会导致元素未渲染完成就执行了操作? - 断言汉堡菜单打开的逻辑是否准确?比如判断的class元素是否在菜单打开后才会出现/状态变化?
排查建议与解决方案(经验分享)
1. 首先修正页面对象类的错误
pages/home_page.py必须是封装元素定位和操作的类,示例如下:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By class HomePage: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 20) # 汉堡按钮定位(请根据实际页面调整) self.burger_trigger = (By.CLASS_NAME, "burger-trigger") # 打开后的汉堡菜单容器定位(请根据实际页面调整) self.opened_burger_menu = (By.CLASS_NAME, "burger.open") def open(self, url): self.driver.get(url) return self def assert_loaded(self): # 显性等待核心元素(汉堡按钮)加载完成,确保页面就绪 self.wait.until(EC.presence_of_element_located(self.burger_trigger)) return self def open_menu(self): # 等待汉堡按钮可点击后再执行点击 self.wait.until(EC.element_to_be_clickable(self.burger_trigger)).click() return self def assert_menu_opened(self): try: # 等待菜单可见,或判断元素属性变化(比如class是否包含open) self.wait.until(EC.visibility_of_element_located(self.opened_burger_menu)) except Exception as e: # 可以添加截图辅助调试 self.driver.save_screenshot("menu_assert_failed.png") raise AssertionError(f"Burger is not open. class='burger'") from e
2. 验证元素定位的准确性
- 用Chrome DevTools(开启模拟器Chrome远程调试)或Appium Inspector查看移动端页面的元素结构,确认:
- 汉堡按钮的实际定位符(class/id/xpath等)
- 菜单打开后,容器元素的class是否有状态变化(比如新增
open类)
- 注意响应式页面的元素差异:移动端和桌面端的汉堡菜单定位可能不同,确保定位的是移动端专属元素
3. 优化等待策略
- 放弃隐式等待,全部改用显性等待,针对每个操作和断言设置足够的超时时间
- 由于页面加载策略是
none,assert_loaded()必须等待核心元素出现后再执行后续操作,避免元素未渲染就触发点击
4. 强制Chrome使用移动端视图
在Appium的ChromeOptions中添加移动端仿真配置,避免模拟器Chrome默认使用桌面视图:
options.set_capability("appium:chromeOptions", { "args": ["--disable-fre", "--no-first-run"], "mobileEmulation": {"deviceName": "Pixel 8"} })
5. 添加调试辅助
在关键步骤添加日志或截图,帮助定位问题:
def open_menu(self): button = self.wait.until(EC.element_to_be_clickable(self.burger_trigger)) print(f"点击前汉堡按钮的class: {button.get_attribute('class')}") button.click() self.driver.save_screenshot("after_click_burger.png") return self
先把页面对象类的错误修正,再从元素定位、等待策略这两个核心点排查,基本就能解决断言失败的问题。如果还有疑问,可以贴出实际页面的元素结构或HomePage类的正确代码,我们再进一步分析~




