乐闻世界logo
搜索文章和话题

Appium 的等待机制有哪些?

2月21日 16:19

Appium 的等待机制是处理异步操作和动态加载的关键功能,确保测试脚本的稳定性和可靠性。以下是 Appium 等待机制的详细说明:

等待类型

Appium 提供了三种主要的等待机制:

1. 隐式等待(Implicit Wait)

设置全局等待时间,在查找元素时自动应用:

javascript
// 设置隐式等待 await driver.manage().timeouts().implicitlyWait(10000); // 10秒 // 查找元素时会自动等待 const element = await driver.findElement(By.id('submit_button'));

特点

  • 全局生效,影响所有元素查找
  • 设置一次,持续有效
  • 可能导致不必要的等待

2. 显式等待(Explicit Wait)

针对特定条件进行等待:

javascript
const { until } = require('selenium-webdriver'); // 等待元素出现 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000 ); // 等待元素可见 await driver.wait( until.elementIsVisible(element), 5000 ); // 等待元素可点击 await driver.wait( until.elementIsClickable(element), 5000 );

特点

  • 针对特定条件
  • 更精确的等待
  • 推荐使用

3. 流畅等待(Fluent Wait)

提供更灵活的等待方式:

javascript
// 使用流畅等待 const element = await driver.wait( async () => { const el = await driver.findElement(By.id('submit_button')); if (el) { return el; } return false; }, 10000, 'Element not found' );

常用等待条件

1. 元素存在

javascript
// 等待元素存在于 DOM 中 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000 );

2. 元素可见

javascript
// 等待元素可见 const element = await driver.findElement(By.id('submit_button')); await driver.wait( until.elementIsVisible(element), 5000 );

3. 元素可点击

javascript
// 等待元素可点击 const element = await driver.findElement(By.id('submit_button')); await driver.wait( until.elementIsClickable(element), 5000 );

4. 元素包含文本

javascript
// 等待元素包含特定文本 await driver.wait( until.elementTextContains(element, 'Submit'), 5000 );

5. 元素属性包含值

javascript
// 等待元素属性包含特定值 await driver.wait( until.elementAttributeContains(element, 'class', 'active'), 5000 );

6. 标题包含文本

javascript
// 等待页面标题包含特定文本 await driver.wait( until.titleContains('Dashboard'), 5000 );

自定义等待条件

1. 基本自定义等待

javascript
// 自定义等待条件 async function waitForElementToBeEnabled(driver, locator, timeout = 10000) { const startTime = Date.now(); while (Date.now() - startTime < timeout) { try { const element = await driver.findElement(locator); const isEnabled = await element.isEnabled(); if (isEnabled) { return element; } } catch (error) { // 元素未找到,继续等待 } await driver.sleep(500); // 等待 500ms } throw new Error(`Element not enabled within ${timeout}ms`); } // 使用自定义等待 const element = await waitForElementToBeEnabled( driver, By.id('submit_button'), 10000 );

2. 复杂自定义等待

javascript
// 等待多个元素 async function waitForMultipleElements(driver, locators, timeout = 10000) { const startTime = Date.now(); const elements = {}; while (Date.now() - startTime < timeout) { let allFound = true; for (const [name, locator] of Object.entries(locators)) { if (!elements[name]) { try { elements[name] = await driver.findElement(locator); } catch (error) { allFound = false; } } } if (allFound) { return elements; } await driver.sleep(500); } throw new Error('Not all elements found within timeout'); } // 使用自定义等待 const elements = await waitForMultipleElements(driver, { submitButton: By.id('submit_button'), cancelButton: By.id('cancel_button') });

等待最佳实践

1. 优先使用显式等待

javascript
// ✅ 推荐:使用显式等待 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000 ); // ❌ 不推荐:使用硬编码等待 await driver.sleep(10000); const element = await driver.findElement(By.id('submit_button'));

2. 合理设置超时时间

javascript
// 根据网络和设备性能调整超时 const timeout = process.env.SLOW_NETWORK ? 20000 : 10000; const element = await driver.wait( until.elementLocated(By.id('submit_button')), timeout );

3. 提供清晰的错误信息

javascript
// 自定义错误信息 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000, 'Submit button not found within 10 seconds' );

4. 组合多个等待条件

javascript
// 等待元素可见且可点击 const element = await driver.findElement(By.id('submit_button')); await driver.wait( until.elementIsVisible(element), 5000 ); await driver.wait( until.elementIsClickable(element), 5000 );

等待常见问题

1. 等待超时

原因

  • 超时时间设置过短
  • 元素定位策略不正确
  • 元素在另一个上下文中

解决方案

javascript
// 增加超时时间 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 20000 ); // 检查上下文 const contexts = await driver.getContexts(); console.log('Available contexts:', contexts); // 切换上下文 await driver.context('WEBVIEW_com.example.app');

2. 不必要的等待

原因

  • 使用了隐式等待
  • 硬编码了等待时间

解决方案

javascript
// 避免使用隐式等待 // await driver.manage().timeouts().implicitlyWait(10000); // 使用显式等待 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000 );

3. 等待条件不明确

原因

  • 等待条件不够具体
  • 没有验证元素状态

解决方案

javascript
// ❌ 不够具体 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000 ); // ✅ 更具体 const element = await driver.findElement(By.id('submit_button')); await driver.wait( until.elementIsVisible(element), 5000 ); await driver.wait( until.elementIsClickable(element), 5000 );

等待性能优化

1. 减少等待时间

javascript
// 使用更精确的等待条件 const element = await driver.wait( until.elementIsVisible(await driver.findElement(By.id('submit_button'))), 5000 );

2. 并行等待

javascript
// 并行等待多个元素 const [element1, element2] = await Promise.all([ driver.wait(until.elementLocated(By.id('button1')), 5000), driver.wait(until.elementLocated(By.id('button2')), 5000) ]);

3. 使用轮询间隔

javascript
// 设置轮询间隔 const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000, 'Element not found', 500 // 轮询间隔 500ms );

最佳实践

  1. 优先使用显式等待

    • 更精确的等待
    • 更好的性能
    • 更清晰的错误信息
  2. 合理设置超时

    • 根据实际情况调整
    • 避免过短或过长
    • 考虑网络和设备性能
  3. 避免硬编码等待

    • 不使用 sleep()
    • 使用条件等待
    • 提高测试稳定性
  4. 处理等待超时

    • 提供清晰的错误信息
    • 实现重试机制
    • 记录超时原因

Appium 的等待机制为测试人员提供了强大的异步操作处理能力,通过合理使用各种等待策略,可以构建稳定、可靠的自动化测试。

标签:Appium