使用Behave+Python在BrowserStack运行Appium测试遇授权错误求助
项目结构
- data
- credentials.yaml
- parameters.yaml
- helpers
- helpers.py
相关文件内容
credentials.yaml
browserstack: userName: "superduperusername" accessKey: "superduperpaccesskey"
parameters.yaml
browserstack_android: platformName: android framework: behave app: bs://roadtoeldorado platforms: - platformName: android deviceName: Samsung Galaxy S22 Ultra platformVersion: 12.0 browserstackLocal: true buildName: bstack-demo projectName: BrowserStack Sample buildIdentifier: ${BUILD_NUMBER} debug: true networkLogs: true
helpers.py
import pprint from appium import webdriver import yaml def create_driver(driver_type): # Read desired capabilities from parameters.yaml based on driver_type with open("data/parameters.yaml", "r") as parameters_file: parameters = yaml.safe_load(parameters_file) with open("data/credentials.yaml", "r") as credentials_file: credentials = yaml.safe_load(credentials_file) if driver_type == 'local_android_emulator': capabilities = parameters.get('local_android_emulator', {}) # Create and return the local driver instance return webdriver.Remote('http://localhost:4723/wd/hub', capabilities) elif driver_type == 'browserstack_android': capabilities = parameters.get('browserstack_android', {}) browserstack_config = credentials.get('browserstack', {}) capabilities.update({ **capabilities, 'browserstack.user': browserstack_config['userName'], 'browserstack.key': browserstack_config['accessKey'], }) # Create and return the BrowserStack driver instance pp = pprint.PrettyPrinter() print("\n") pp.pprint(capabilities) return webdriver.Remote( command_executor="https://hub-cloud.browserstack.com/wd/hub", desired_capabilities=capabilities ) # Add more cases for other driver types if needed else: raise ValueError(f"Unsupported driver type: {driver_type}")
environment.py
import os from helpers.helpers import create_driver def before_scenario(context, scenario): # Check for the environment variable to set the execution mode execution_mode = os.environ.get("EXECUTION_MODE", "local_android_emulator") context.execution_mode = execution_mode # Set up the driver based on execution mode if context.execution_mode == "local_android_emulator": context.driver = create_driver('local_android_emulator') elif context.execution_mode == "browserstack_android": context.driver = create_driver('browserstack_android') else: raise ValueError(f"Unsupported execution mode: {execution_mode}") # Add more modes as needed def after_scenario(context, scenario): # Quit the driver after all scenarios have finished if hasattr(context, "driver") and context.driver: context.driver.quit()
打印的Capabilities
{'app': 'bs://roadtoeldorado', 'browserstack.key': 'superduperkey', 'browserstack.user': 'superduperusername', 'browserstackLocal': True, 'buildIdentifier': '${BUILD_NUMBER}', 'buildName': 'bstack-demo', 'debug': True, 'framework': 'behave', 'networkLogs': True, 'platformName': 'android', 'platforms': [{'deviceName': 'Samsung Galaxy S22 Ultra', 'platformName': 'android', 'platformVersion': 12.0}], 'projectName': 'BrowserStack Sample'}
运行错误
HOOK-ERROR in before_scenario: WebDriverException: Message: Authorization required
用户尝试过改用JSON格式调用,问题依旧;直接把凭据放入URL认证时,会出现"missing deviceName"错误,怀疑是Capabilities传递有误,寻求问题原因及解决方法。
1. 修正凭据不匹配问题
从打印的Capabilities可以看到,browserstack.key的值是superduperkey,但credentials.yaml里的accessKey是superduperpaccesskey,二者完全不匹配,这是授权失败的直接原因。需要将credentials.yaml中的accessKey修改为正确的BrowserStack密钥,或者排查代码中是否存在拼写错误。
2. 调整Capabilities结构
BrowserStack不支持在Capabilities中嵌套platforms数组,必须将设备参数(deviceName、platformVersion)直接放在顶层。修改parameters.yaml:
browserstack_android: platformName: android framework: behave app: bs://roadtoeldorado deviceName: Samsung Galaxy S22 Ultra platformVersion: 12.0 browserstackLocal: true buildName: bstack-demo projectName: BrowserStack Sample buildIdentifier: ${BUILD_NUMBER} debug: true networkLogs: true
3. 简化Capabilities更新逻辑
当前代码中capabilities.update({**capabilities, ...})属于冗余写法,直接添加新键值对即可,避免不必要的解构操作:
capabilities.update({ 'browserstack.user': browserstack_config['userName'], 'browserstack.key': browserstack_config['accessKey'], })
4. 处理占位符替换
${BUILD_NUMBER}是环境变量占位符,需要确保运行测试时该变量已被替换为实际值,否则可能导致BrowserStack无法识别构建信息,间接影响授权或设备匹配。
5. 验证BrowserStack Local状态
如果启用了browserstackLocal: true,必须确保BrowserStack Local二进制文件已正确启动并完成连接,未启动的话也会导致连接或授权失败。
内容的提问来源于stack exchange,提问作者vesssori

