研发协作
用 Selenium WebDriver…
需要对 Web 应用进行跨浏览器/无头浏览器自动化测试,并处理动态内容等待、元素定位与测试组织时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
用 Selenium WebDriver特定
解决思路
- 覆盖并实现以下能力:Selenium WebDriver 架构与浏览器驱动、元素定位策略(ID、CSS、XPath、link text)、显式与隐式等待、Page Object Model(POM)、跨 Chrome/Firefox/Safari/Edge 测试、无头浏览器执行、与 pytest/unittest 集成、用 Grid 部署并行测试。
- 按 PEP 8 编写可维护、可读的测试代码。
- 使用 Page Object Model 模式实现代码复用。
- 使用显式等待,不要用隐式等待或硬编码 sleep。
- 设计相互独立、隔离的测试。
- 正确处理动态内容和异步操作。
- 通过辅助函数和基类遵循 DRY 原则。
- 创建项目结构:tests/conftest.py;tests/pages/__init__.py、base_page.py、login_page.py、dashboard_page.py;tests/tests/__init__.py、test_login.py、test_dashboard.py;tests/utils/__init__.py、driver_factory.py、config.py。
- 实现驱动工厂:create_driver(browser='chrome', headless=False);Chrome 下创建 Options,headless 为 True 时 add_argument('--headless'),并 add_argument('--no-sandbox') 与 add_argument('--disable-dev-shm-usage');用 Service(ChromeDriverManager().install()) 创建 service,返回 webdriver.Chrome(service=service, options=options);需要时扩展其他浏览器。
- 编写 pytest fixture:@pytest.fixture(scope='function') def driver(): 调用 create_driver(headless=True),执行 driver.implicitly_wait(10),yield driver,最后 driver.quit()。
- 实现 BasePage:__init__(self, driver) 保存 driver,并创建 self.wait = WebDriverWait(driver, 10)。
- 实现 BasePage.find_element:用 self.wait.until(EC.presence_of_element_located(locator)) 返回元素。
- 实现 BasePage.click_element:用 self.wait.until(EC.element_to_be_clickable(locator)) 获取元素后 click()。
- 实现 BasePage.enter_text:先 find_element(locator),再 clear(),再 send_keys(text)。
- 实现页面对象:如 LoginPage(BasePage),定义定位器 USERNAME_INPUT=(By.ID, 'username')、PASSWORD_INPUT=(By.ID, 'password')、LOGIN_BUTTON=(By.CSS_SELECTOR, 'button[type="submit"]')、ERROR_MESSAGE=(By.CLASS_NAME, 'error-message');__init__ 调 super 并保存 url='/login'。
- 实现 LoginPage.login:对用户名和密码调用 enter_text,再 click_element(LOGIN_BUTTON)。
- 实现 LoginPage.get_error_message:返回 find_element(ERROR_MESSAGE).text。
- 元素定位优先级按可靠性从高到低:ID、Name、CSS Selector、XPath、Link Text、Class Name;尽量选靠前的定位方式,Class Name 频繁变化时避免使用。
- CSS Selector 最佳实践:使用具体、稳定的选择器,例如 By.CSS_SELECTOR, 'form#login input[name="username"]' 和 By.CSS_SELECTOR, '[data-testid="submit-button"]'。
- CSS Selector 避免使用:过于结构化的选择器如 'div > div > div > button',以及可能变化的类如 '.btn-primary'。
- XPath 最佳实践:用于复杂关系,例如 By.XPATH, '//label[text()="Email"]/following-sibling::input' 和 By.XPATH, '//table//tr[contains(., "John")]//button[@class="edit"]'。
- 显式等待:创建 wait = WebDriverWait(driver, 10),用 wait.until(EC.element_to_be_clickable((By.ID, 'button'))) 等待可点击。
- 等待可见:wait.until(EC.visibility_of_element_located((By.ID, 'modal')))。
- 等待文本出现:wait.until(EC.text_to_be_present_in_element((By.ID, 'status'), 'Complete'))。
- 自定义等待条件:wait.until(lambda d: d.find_element(By.ID, 'count').text == '5')。
- 使用常见 expected conditions:presence_of_element_located(元素存在于 DOM)、visibility_of_element_located(元素可见)、element_to_be_clickable(元素可见且启用)、staleness_of(元素不再附加到 DOM)、frame_to_be_available_and_switch_to_it(frame 可用并切换)。
- 测试结构:用 @pytest.fixture(autouse=True) 的 setup(self, driver) 保存 driver,并实例化 LoginPage(driver)、DashboardPage(driver)。
- 测试成功登录:driver.get('https://example.com/login'),login_page.login('valid_user', 'valid_pass'),断言 dashboard_page.is_displayed()。
- 测试无效密码:driver.get('https://example.com/login'),login_page.login('valid_user', 'wrong_pass'),断言 'Invalid credentials' in login_page.get_error_message()。
- 测试命名使用描述性名称,如 test_login_with_valid_credentials_redirects_to_dashboard,包含动作和预期结果;相关测试按类分组。
- 处理下拉框:select = Select(driver.find_element(By.ID, 'country'));使用 select_by_visible_text('United States')、select_by_value('us')、select_by_index(1)。
- 处理 Alert:alert = driver.switch_to.alert;用 alert.accept() 点击 OK,alert.dismiss() 点击 Cancel,alert.send_keys('input text') 在 prompt 中输入。
- 处理 Frame:driver.switch_to.frame('frame_name'),或先 frame = driver.find_element(By.ID, 'myframe') 再 driver.switch_to.frame(frame);完成后 driver.switch_to.default_content()。
- 处理多窗口:original_window = driver.current_window_handle;点击打开新窗口的链接后,遍历 driver.window_handles,找到 != original_window 的 handle 并 driver.switch_to.window(handle);完成后 driver.switch_to.window(original_window)。
- 性能与可靠性:用 headless 模式运行测试以加快执行。
- 性能与可靠性:用 pytest-xdist 并行执行测试。
- 性能与可靠性:对不稳定测试实现重试逻辑。
- 性能与可靠性:失败时截图以便调试。
- 性能与可靠性:用 WebDriverWait 替代 time.sleep()。
- 安装/使用关键依赖:selenium、webdriver-manager、pytest、pytest-xdist(并行执行)、pytest-html(HTML 报告)、allure-pytest(高级报告)。
- 配置 pytest.ini:[pytest] addopts = -v --html=reports/report.html;markers = smoke: Quick smoke tests, regression: Full regression tests。
- 调试:在非 headless 模式下启用浏览器开发者工具。
- 调试:用 driver.save_screenshot('debug.png') 做可视化调试。
- 调试:打印页面源码:print(driver.page_source)。
- 调试:用断点:import pdb; pdb.set_trace()。
适用边界 · 注意事项
- 当项目主要使用现代前端框架且需要更稳定的自动等待与网络拦截时,优先考虑 Playwright、Cypress 等更现代的端到端测试工具。
- 只做 HTTP API 测试、不需要真实浏览器渲染时,不需要使用 Selenium WebDriver。
- 无法安装浏览器、浏览器驱动或无法运行有头/无头浏览器环境时,不适合使用。