使用pytest-xdist并行执行Selenium测试时,仅启动单Chrome实例多标签的问题
问题:pytest-xdist并行执行Selenium测试时无法启动独立Chrome实例
我编写了3个Selenium测试用例,希望通过pytest-xdist并行执行,每个测试用例对应启动一个独立的Chrome实例,但实际只启动了一个实例并打开3个标签页,仅第一个标签页完成页面导航,其余标签页为空。
测试代码如下:
from time import sleep from selenium import webdriver from selenium.webdriver import ChromeOptions port = 4444 command_executor = 'http://127.0.0.1:%s/wd/hub' % port options = ChromeOptions() options.add_argument('--start-maximized') options.add_argument('--no-sandbox') options.add_argument('--autoplay-policy=no-user-gesture-required') options.add_argument('--remote-debugging-port=9222') def test_a(): driver = webdriver.Remote( command_executor=command_executor, options=options ) driver.get('https://www.amazon.com/') sleep(10) def test_b(): driver = webdriver.Remote( command_executor=command_executor, options=options ) driver.get('https://google.com') sleep(10) def test_c(): driver = webdriver.Remote( command_executor=command_executor, options=options ) driver.get('https://facebook.com/') sleep(10)
执行命令:
py.test -n 3 tests/tests
环境信息:
- Python版本:3.11.4
- pytest-xdist版本:3.3.1
- Selenium Server启动命令:
java -jar selenium-server-4.10.0.jar standalone
解决方案
1. 移除固定的--remote-debugging-port参数
问题核心是所有测试用例共享了同一个固定调试端口9222,第一个Chrome实例启动后占用该端口,后续测试会复用这个实例而非启动新实例。直接删除该参数即可,Selenium Server会自动为每个会话分配独立的调试端口。
2. 确保每个测试使用独立的ChromeOptions实例
全局options变量可能在并行执行时出现状态共享问题,建议通过函数或fixture为每个测试生成独立的配置实例。
3. 测试结束后主动关闭driver
未关闭driver会导致会话残留,浪费资源且可能影响后续测试,需在测试末尾调用driver.quit(),或用pytest fixture自动管理生命周期。
修改后的代码示例(基础版)
from time import sleep from selenium import webdriver from selenium.webdriver import ChromeOptions port = 4444 command_executor = 'http://127.0.0.1:%s/wd/hub' % port def get_chrome_options(): options = ChromeOptions() options.add_argument('--start-maximized') options.add_argument('--no-sandbox') options.add_argument('--autoplay-policy=no-user-gesture-required') # 移除固定调试端口参数 return options def test_a(): driver = webdriver.Remote( command_executor=command_executor, options=get_chrome_options() ) try: driver.get('https://www.amazon.com/') sleep(10) finally: driver.quit() def test_b(): driver = webdriver.Remote( command_executor=command_executor, options=get_chrome_options() ) try: driver.get('https://google.com') sleep(10) finally: driver.quit() def test_c(): driver = webdriver.Remote( command_executor=command_executor, options=get_chrome_options() ) try: driver.get('https://facebook.com/') sleep(10) finally: driver.quit()
更优雅的Fixture版本
import pytest from time import sleep from selenium import webdriver from selenium.webdriver import ChromeOptions port = 4444 command_executor = 'http://127.0.0.1:%s/wd/hub' % port @pytest.fixture(scope="function") def driver(): options = ChromeOptions() options.add_argument('--start-maximized') options.add_argument('--no-sandbox') options.add_argument('--autoplay-policy=no-user-gesture-required') driver_instance = webdriver.Remote( command_executor=command_executor, options=options ) yield driver_instance # 测试结束自动关闭driver driver_instance.quit() def test_a(driver): driver.get('https://www.amazon.com/') sleep(10) def test_b(driver): driver.get('https://google.com') sleep(10) def test_c(driver): driver.get('https://facebook.com/') sleep(10)
修改后执行原命令py.test -n 3 tests/tests即可实现每个测试用例启动独立的Chrome实例。
内容的提问来源于stack exchange,提问作者sridhar249
相关产品推荐
相关产品推荐

