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

面试题手册

Appium 的 Desired Capabilities 是什么?

Appium 的 Desired Capabilities 是配置测试会话的关键参数,用于指定测试环境、应用和自动化行为。以下是 Appium Desired Capabilities 的详细说明:基本概念Desired Capabilities 是一组键值对,用于告诉 Appium Server:在哪个平台上运行测试使用哪个设备或模拟器启动哪个应用如何配置自动化行为通用 Capabilities平台相关const capabilities = { platformName: 'Android', // 平台名称 platformVersion: '11.0', // 平台版本 deviceName: 'Pixel 5', // 设备名称 automationName: 'UiAutomator2' // 自动化引擎};说明:platformName:必需,指定平台(Android、iOS、Windows)platformVersion:可选,指定操作系统版本deviceName:必需,指定设备或模拟器名称automationName:可选,指定自动化引擎应用相关const capabilities = { app: '/path/to/app.apk', // 应用文件路径 appPackage: 'com.example.app', // Android 包名 appActivity: '.MainActivity', // Android Activity bundleId: 'com.example.app', // iOS Bundle ID autoLaunch: true, // 自动启动应用 noReset: true, // 不重置应用状态 fullReset: false // 不完全重置};说明:app:应用文件的本地路径或 URLappPackage:Android 应用的包名appActivity:Android 应用的启动 ActivitybundleId:iOS 应用的 Bundle IDautoLaunch:是否自动启动应用noReset:测试前不重置应用状态fullReset:测试前是否完全重置Android 特定 Capabilitiesconst capabilities = { platformName: 'Android', automationName: 'UiAutomator2', // 应用配置 appPackage: 'com.example.app', appActivity: '.MainActivity', appWaitPackage: 'com.example.app', appWaitActivity: '.MainActivity', // 设备配置 deviceName: 'Android Emulator', platformVersion: '11.0', udid: 'emulator-5554', // 浏览器测试 browserName: 'Chrome', // 权限配置 autoGrantPermissions: true, autoWebview: false, // 其他配置 ignoreUnimportantViews: false, disableWindowAnimation: false, skipServerInstallation: false, skipDeviceInitialization: false};关键参数:udid:设备的唯一标识符autoGrantPermissions:自动授予应用权限ignoreUnimportantViews:忽略不重要的视图disableWindowAnimation:禁用窗口动画iOS 特定 Capabilitiesconst capabilities = { platformName: 'iOS', automationName: 'XCUITest', // 应用配置 bundleId: 'com.example.app', app: '/path/to/app.ipa', // 设备配置 deviceName: 'iPhone 14', platformVersion: '16.0', udid: 'auto', // 模拟器配置 wdaStartupRetries: 4, wdaLocalPort: 8100, usePrebuiltWDA: false, wdaConnectionTimeout: 60000, // 其他配置 showXcodeLog: false, xcodeOrgId: 'TEAM_ID', xcodeSigningId: 'iPhone Developer', updatedWDABundleId: 'com.example.app.WebDriverAgentRunner'};关键参数:udid:设备的唯一标识符(真机)或 'auto'(模拟器)wdaStartupRetries:WebDriverAgent 启动重试次数wdaLocalPort:WebDriverAgent 本地端口usePrebuiltWDA:使用预构建的 WebDriverAgentxcodeOrgId:Xcode 团队 ID(真机测试)xcodeSigningId:Xcode 签名 ID(真机测试)会话配置 Capabilitiesconst capabilities = { // 超时配置 newCommandTimeout: 60, // 新命令超时时间(秒) commandTimeouts: { implicit: 0, // 隐式等待超时 pageLoad: 300000, // 页面加载超时 script: 30000 // 脚本执行超时 }, // 语言和区域 language: 'zh-CN', locale: 'zh_CN', // 时区 timezone: 'Asia/Shanghai', // 其他配置 clearSystemFiles: true, eventTimings: true, enableMultiWindows: false};性能优化 Capabilitiesconst capabilities = { // 跳过不必要的步骤 skipServerInstallation: false, skipDeviceInitialization: false, skipUninstall: false, // 禁用动画 disableWindowAnimation: true, ignoreUnimportantViews: true, // 优化性能 nativeWebScreenshot: true, screenshotQuality: 0, mjpegScreenshotUrl: 'http://localhost:8080/stream'};调试 Capabilitiesconst capabilities = { // 日志配置 showXcodeLog: true, androidInstallTimeout: 90000, uiautomator2ServerInstallTimeout: 200000, // 调试模式 debugLogSpacing: true, suppressKillServer: false, // 详细日志 systemPort: 8200, mjpegServerPort: 7810};最佳实践1. 合理配置 Capabilities// 使用环境变量const capabilities = { platformName: process.env.PLATFORM_NAME || 'Android', deviceName: process.env.DEVICE_NAME || 'emulator-5554', app: process.env.APP_PATH || '/path/to/app.apk'};2. 分离平台配置// android.config.jsmodule.exports = { platformName: 'Android', automationName: 'UiAutomator2', appPackage: 'com.example.app', appActivity: '.MainActivity'};// ios.config.jsmodule.exports = { platformName: 'iOS', automationName: 'XCUITest', bundleId: 'com.example.app'};// 根据平台选择配置const platform = process.env.PLATFORM || 'Android';const capabilities = require(`./${platform.toLowerCase()}.config.js`);3. 使用默认值const defaultCapabilities = { newCommandTimeout: 60, autoLaunch: true, noReset: false, fullReset: false};const capabilities = { ...defaultCapabilities, platformName: 'Android', deviceName: 'Pixel 5'};4. 验证 Capabilitiesfunction validateCapabilities(capabilities) { const required = ['platformName', 'deviceName', 'automationName']; const missing = required.filter(key => !capabilities[key]); if (missing.length > 0) { throw new Error(`Missing required capabilities: ${missing.join(', ')}`); } return capabilities;}const capabilities = validateCapabilities({ platformName: 'Android', deviceName: 'Pixel 5', automationName: 'UiAutomator2'});常见问题找不到元素:检查 automationName 是否正确确认应用已正确启动验证元素定位策略应用启动失败:检查 appPackage 和 appActivity 是否正确确认应用文件路径正确查看日志了解详细错误权限问题:设置 autoGrantPermissions: true手动授予必要权限检查应用权限配置Appium 的 Desired Capabilities 为测试人员提供了灵活的配置方式,通过合理配置,可以满足各种测试场景的需求。
阅读 0·2月21日 16:19

Appium 如何进行移动 Web 测试?

Appium 的移动 Web 测试是移动应用自动化测试的重要组成部分,用于测试移动浏览器中的 Web 应用。以下是 Appium 移动 Web 测试的详细说明:移动 Web 测试概述什么是移动 Web 测试移动 Web 测试是指使用移动设备的浏览器来测试 Web 应用程序:使用移动设备的原生浏览器(如 Chrome、Safari)测试响应式设计和移动优化验证 Web 应用在移动设备上的功能和性能移动 Web 测试场景// 移动 Web 测试常见场景{ "testScenarios": [ "响应式布局测试", "触摸交互测试", "移动性能测试", "跨浏览器兼容性测试", "移动端用户体验测试" ]}浏览器配置1. Android Chrome 浏览器// Android Chrome 浏览器配置const capabilities = { platformName: 'Android', deviceName: 'Pixel 5', browserName: 'Chrome', platformVersion: '11.0', udid: 'emulator-5554'};const driver = await new Builder() .withCapabilities(capabilities) .build();// 访问 Web 应用await driver.get('https://example.com');2. iOS Safari 浏览器// iOS Safari 浏览器配置const capabilities = { platformName: 'iOS', deviceName: 'iPhone 14', browserName: 'Safari', platformVersion: '16.0', udid: 'auto'};const driver = await new Builder() .withCapabilities(capabilities) .build();// 访问 Web 应用await driver.get('https://example.com');3. 高级浏览器配置// Android Chrome 高级配置const capabilities = { platformName: 'Android', deviceName: 'Pixel 5', browserName: 'Chrome', platformVersion: '11.0', // Chrome 选项 chromeOptions: { args: [ '--disable-popup-blocking', '--disable-infobars', '--start-maximized' ], prefs: { 'profile.default_content_setting_values.notifications': 2 } }, // 性能优化 nativeWebScreenshot: true, screenshotQuality: 0};// iOS Safari 高级配置const capabilities = { platformName: 'iOS', deviceName: 'iPhone 14', browserName: 'Safari', platformVersion: '16.0', // Safari 选项 safariIgnoreFraudWarning: true, safariInitialUrl: 'https://example.com', safariAllowPopups: true, safariOpenLinksInBackground: false};元素定位1. 标准 WebDriver 定位策略// 使用 ID 定位const element = await driver.findElement(By.id('submit_button'));await element.click();// 使用 CSS 选择器const element = await driver.findElement(By.css('.submit-btn'));await element.click();// 使用 XPathconst element = await driver.findElement(By.xpath('//button[@id="submit_button"]'));await element.click();// 使用类名const element = await driver.findElement(By.className('btn-primary'));await element.click();// 使用标签名const element = await driver.findElement(By.tagName('button'));await element.click();// 使用名称const element = await driver.findElement(By.name('submit'));await element.click();// 使用链接文本const element = await driver.findElement(By.linkText('Submit'));await element.click();// 使用部分链接文本const element = await driver.findElement(By.partialLinkText('Sub'));await element.click();2. 移动端特定定位// 使用触摸元素定位const element = await driver.findElement(By.css('[touch-action="manipulation"]'));// 使用响应式元素定位const element = await driver.findElement(By.css('@media (max-width: 768px) .mobile-button'));移动端交互1. 触摸操作// 点击操作const element = await driver.findElement(By.id('submit_button'));await element.click();// 双击操作const actions = driver.actions({ async: true });await actions.move({ origin: element }).doubleClick().perform();// 长按操作const actions = driver.actions({ async: true });await actions.move({ origin: element }).press().pause(2000).release().perform();2. 滑动操作// 滑动操作const size = await driver.manage().window().getRect();const startX = size.width / 2;const startY = size.height * 0.8;const endY = size.height * 0.2;await driver.touchActions([ { action: 'press', x: startX, y: startY }, { action: 'moveTo', x: startX, y: endY }, { action: 'release' }]);// 使用 JavaScript 滚动await driver.executeScript('window.scrollTo(0, 1000);');3. 缩放操作// 缩放操作const actions = driver.actions({ async: true });await actions .move({ origin: element }) .press() .move({ origin: element, x: 50, y: 0 }) .release() .perform();响应式设计测试1. 测试不同屏幕尺寸// 测试不同屏幕尺寸const screenSizes = [ { width: 375, height: 667 }, // iPhone SE { width: 414, height: 896 }, // iPhone 11 { width: 360, height: 640 }, // Android 小屏 { width: 412, height: 915 } // Android 大屏];for (const size of screenSizes) { // 设置窗口大小 await driver.manage().window().setRect({ width: size.width, height: size.height }); // 测试响应式布局 const element = await driver.findElement(By.css('.responsive-element')); const isVisible = await element.isDisplayed(); console.log(`Screen ${size.width}x${size.height}: Element visible: ${isVisible}`);}2. 测试横竖屏切换// 测试横竖屏切换async function testOrientation() { // 竖屏模式 await driver.rotateScreen('PORTRAIT'); const portraitElement = await driver.findElement(By.css('.portrait-element')); const portraitVisible = await portraitElement.isDisplayed(); console.log('Portrait mode:', portraitVisible); // 横屏模式 await driver.rotateScreen('LANDSCAPE'); const landscapeElement = await driver.findElement(By.css('.landscape-element')); const landscapeVisible = await landscapeElement.isDisplayed(); console.log('Landscape mode:', landscapeVisible);}await testOrientation();性能测试1. 页面加载时间// 测量页面加载时间async function measurePageLoadTime(driver, url) { const startTime = Date.now(); await driver.get(url); const endTime = Date.now(); const loadTime = endTime - startTime; console.log(`Page load time: ${loadTime}ms`); return loadTime;}const loadTime = await measurePageLoadTime(driver, 'https://example.com');assert(loadTime < 3000, 'Page load time should be less than 3 seconds');2. 资源加载时间// 获取性能指标const metrics = await driver.executeScript(` return window.performance.timing;`);const pageLoadTime = metrics.loadEventEnd - metrics.navigationStart;const domContentLoaded = metrics.domContentLoadedEventEnd - metrics.navigationStart;console.log('Page load time:', pageLoadTime);console.log('DOM content loaded:', domContentLoaded);3. 网络性能// 使用 Chrome DevTools Protocolconst performance = await driver.getPerformanceMetrics();console.log('Performance metrics:', performance);// 获取网络日志const logs = await driver.manage().logs().get('performance');console.log('Network logs:', logs);跨浏览器测试1. 多浏览器测试// 测试多个浏览器const browsers = [ { browserName: 'Chrome', platformName: 'Android' }, { browserName: 'Safari', platformName: 'iOS' }];for (const browser of browsers) { const capabilities = { ...browser, deviceName: 'Test Device', platformVersion: 'latest' }; const driver = await new Builder() .withCapabilities(capabilities) .build(); try { await driver.get('https://example.com'); // 执行测试 } finally { await driver.quit(); }}2. 浏览器兼容性测试// 测试浏览器兼容性async function testBrowserCompatibility(driver, url) { await driver.get(url); // 检查元素是否正确显示 const element = await driver.findElement(By.id('main-content')); const isVisible = await element.isDisplayed(); assert(isVisible, 'Element should be visible'); // 检查样式是否正确 const backgroundColor = await element.getCssValue('background-color'); console.log('Background color:', backgroundColor); // 检查交互是否正常 const button = await driver.findElement(By.id('submit_button')); await button.click(); const result = await driver.findElement(By.id('result_message')); const text = await result.getText(); assert.strictEqual(text, 'Success');}移动端特定功能测试1. 触摸手势测试// 测试触摸手势async function testTouchGestures(driver) { // 测试点击 const element = await driver.findElement(By.id('button')); await element.click(); // 测试滑动 const size = await driver.manage().window().getRect(); await driver.touchActions([ { action: 'press', x: size.width / 2, y: size.height * 0.8 }, { action: 'moveTo', x: size.width / 2, y: size.height * 0.2 }, { action: 'release' } ]); // 测试长按 await driver.touchActions([ { action: 'press', x: size.width / 2, y: size.height / 2 }, { action: 'wait', ms: 2000 }, { action: 'release' } ]);}2. 设备方向测试// 测试设备方向async function testDeviceOrientation(driver) { // 测试竖屏 await driver.rotateScreen('PORTRAIT'); const portraitElement = await driver.findElement(By.css('.portrait-only')); const portraitVisible = await portraitElement.isDisplayed(); console.log('Portrait element visible:', portraitVisible); // 测试横屏 await driver.rotateScreen('LANDSCAPE'); const landscapeElement = await driver.findElement(By.css('.landscape-only')); const landscapeVisible = await landscapeElement.isDisplayed(); console.log('Landscape element visible:', landscapeVisible);}3. 网络状态测试// 测试网络状态async function testNetworkConditions(driver) { // 设置网络速度 await driver.setNetworkConditions({ offline: false, latency: 100, // 100ms 延迟 download_throughput: 500 * 1024, // 500KB/s upload_throughput: 500 * 1024 // 500KB/s }); // 测试页面加载 const startTime = Date.now(); await driver.get('https://example.com'); const loadTime = Date.now() - startTime; console.log('Load time with slow network:', loadTime); // 恢复正常网络 await driver.setNetworkConditions({ offline: false, latency: 0, download_throughput: -1, upload_throughput: -1 });}最佳实践1. 使用 Page Object 模式// Page Object 模式class MobileWebPage { constructor(driver) { this.driver = driver; } async open(url) { await this.driver.get(url); } async fillForm(data) { for (const [key, value] of Object.entries(data)) { const input = await this.driver.findElement(By.id(key)); await input.clear(); await input.sendKeys(value); } } async submit() { const button = await this.driver.findElement(By.id('submit_button')); await button.click(); } async getResult() { const result = await this.driver.findElement(By.id('result_message')); return await result.getText(); }}// 使用 Page Objectconst page = new MobileWebPage(driver);await page.open('https://example.com');await page.fillForm({ username: 'test', password: 'password' });await page.submit();const result = await page.getResult();2. 响应式测试// 响应式测试套件async function runResponsiveTests(driver) { const screenSizes = [ { name: 'Mobile', width: 375, height: 667 }, { name: 'Tablet', width: 768, height: 1024 }, { name: 'Desktop', width: 1920, height: 1080 } ]; for (const size of screenSizes) { console.log(`Testing on ${size.name} (${size.width}x${size.height})`); await driver.manage().window().setRect({ width: size.width, height: size.height }); // 执行测试 await testResponsiveLayout(driver); }}3. 性能监控// 性能监控async function monitorPerformance(driver) { const metrics = await driver.executeScript(` return { loadTime: window.performance.timing.loadEventEnd - window.performance.timing.navigationStart, domContentLoaded: window.performance.timing.domContentLoadedEventEnd - window.performance.timing.navigationStart, firstPaint: window.performance.timing.responseStart - window.performance.timing.navigationStart }; `); console.log('Performance metrics:', metrics); // 验证性能指标 assert(metrics.loadTime < 3000, 'Page load time should be less than 3 seconds'); assert(metrics.domContentLoaded < 1500, 'DOM content loaded should be less than 1.5 seconds');}常见问题1. 浏览器启动失败问题:无法启动浏览器解决方案:// 检查浏览器是否安装// Android: 检查 Chrome 是否安装// iOS: 检查 Safari 是否可用// 使用正确的 browserNameconst capabilities = { platformName: 'Android', browserName: 'Chrome', // 确保浏览器名称正确 deviceName: 'Pixel 5'};2. 元素定位失败问题:无法定位元素解决方案:// 等待元素加载const element = await driver.wait( until.elementLocated(By.id('submit_button')), 10000);// 检查元素是否在视口中await driver.executeScript('arguments[0].scrollIntoView(true);', element);// 使用更精确的定位策略const element = await driver.findElement(By.css('#submit_button.btn-primary'));3. 触摸操作不响应问题:触摸操作没有响应解决方案:// 使用 JavaScript 点击await driver.executeScript('arguments[0].click();', element);// 使用坐标点击const rect = await element.getRect();const x = rect.x + rect.width / 2;const y = rect.y + rect.height / 2;await driver.touchActions([{ action: 'tap', x: x, y: y }]);Appium 的移动 Web 测试为测试人员提供了强大的移动浏览器自动化能力,通过合理的测试策略和最佳实践,可以构建全面、可靠的移动 Web 测试。
阅读 0·2月21日 16:19

ASCII 码在编程中的常见应用场景

ASCII 码在编程中的常见应用场景:1. 字符验证:# 验证是否为字母def is_letter(char): return 'A' <= char <= 'Z' or 'a' <= char <= 'z'# 验证是否为数字def is_digit(char): return '0' <= char <= '9'# 验证是否为可打印字符def is_printable(char): return 32 <= ord(char) <= 1262. 字符转换:# 大小写转换def to_upper(char): if 'a' <= char <= 'z': return chr(ord(char) - 32) return chardef to_lower(char): if 'A' <= char <= 'Z': return chr(ord(char) + 32) return char3. 字符串处理:# 移除空白字符def trim_whitespace(s): return s.strip() # 移除空格(32)、制表符(9)、换行符(10/13)等# 统计字符类型def count_chars(s): letters = digits = others = 0 for c in s: if 'A' <= c <= 'Z' or 'a' <= c <= 'z': letters += 1 elif '0' <= c <= '9': digits += 1 else: others += 1 return letters, digits, others4. 数据编码:# Base64 编码(基于 ASCII)import base64encoded = base64.b64encode(b'Hello').decode('ascii')# URL 编码from urllib.parse import quoteencoded = quote('Hello World', safe='')5. 网络协议:HTTP 头部使用 ASCII 编码SMTP、FTP 等协议基于 ASCIIJSON 字符串使用 ASCII 字符6. 文件处理:# 读取 ASCII 文本文件with open('file.txt', 'r', encoding='ascii') as f: content = f.read()注意事项:处理非 ASCII 字符时使用 Unicode注意换行符差异(CRLF vs LF)验证输入字符的有效性
阅读 0·2月21日 16:18