使用Selenium/Appium时出现Session ID is null错误,求解决方法
问题排查:Session ID is null. Using WebDriver after calling quit()?
错误信息
org.openqa.selenium.WebDriverException: org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()? Build info: version: '4.8.2', revision: '826dbfc730' System info: os.name: 'Mac OS X', os.arch: 'aarch64', os.version: '13.2.1', java.version: '1.8.0_362' Driver info: io.appium.java_client.android.AndroidDriver Command: [null, findElement {using=xpath, value=//*[@text='Enter PIN']}] Capabilities {appium:app: /Users/chandan/Desktop/mobi..., appium:appActivity: com.comviva.mobiquityconsum..., appium:appPackage: com.comviva.mobiquity.consu..., appium:autoGrantPermissions: true, appium:automationName: UiAutomator2, appium:clearDeviceLogsOnStart: true, appium:databaseEnabled: false, appium:desired: {app: /Users/chandan/Desktop/mobi..., appium:appActivity: com.comviva.mobiquityconsum..., appium:appPackage: com.comviva.mobiquity.consu..., autoGrantPermissions: true, automationName: UiAutomator2, clearDeviceLogsOnStart: true, deviceName: Pixel5, eventTimings: true, ignoreHiddenApiPolicyError: true, newCommandTimeout: 30000, noReset: false, platformName: android, platformVersion: 12, udid: emulator-5554}, appium:deviceApiLevel: 31, appium:deviceManufacturer: Google, appium:deviceModel: sdk_gphone64_arm64, appium:deviceName: emulator-5554, appium:deviceScreenDensity: 440, appium:deviceScreenSize: 1080x2340, appium:deviceUDID: emulator-5554, appium:eventTimings: true, appium:ignoreHiddenApiPolicyError: true, appium:javascriptEnabled: true, appium:locationContextEnabled: false, appium:networkConnectionEnabled: true, appium:newCommandTimeout: 30000, appium:noReset: false, appium:pixelRatio: 2.75, appium:platformVersion: 12, appium:statBarHeight: 145, appium:takesScreenshot: true, appium:udid: emulator-5554, appium:viewportRect: {height: 1927, left: 0, top: 145, width: 1080}, appium:warnings: {}, appium:webStorageEnabled: false, platformName: ANDROID}
测试类代码
@AfterMethod public void tearDown(){ DriverFactory.quitDriver(); } @BeforeMethod public void startDriver(){ DriverFactory.getMobileAppDriver(); } @Test(priority = 1) public void InvalidLogin(){ ExtentManager.startTestFromProperty(pNode, TestCases.getTestCase("SMOKE_TC_07")); startPositveTest(); login.login(DataDriven.getUserByStatus("Y"),"1234"); } @Test(priority = 2) public void ElectricBill(){ ExtentManager.startTestFromProperty(pNode, TestCases.getTestCase("SMOKE_TC_02")); startPositveTest(); login.enterPin(DataDriven.getUserPinByStatus("Y")); billPay.electricityBillPay("50","OD23432123",DataDriven.getUserPinByStatus("Y")); }
Driver Factory代码
public class DriverFactory { private static WebDriver driver; private static AppiumDriver mobileDriver; private static final Logger logger = LoggerFactory.getLogger(DriverFactory.class); public static AppiumDriver getMobileAppDriver(){ try{ if(mobileDriver != null){ return mobileDriver; } if (MobileProperties.getProperty("device.platform").equalsIgnoreCase("android")) { mobileDriver = MobileDriver.getAndroidDriver(); logger.info("Info : "); } else { mobileDriver = MobileDriver.getIOSDriver(); } } catch (Exception e){ e.printStackTrace(); } return mobileDriver; } public static void quitDriver() { if (mobileDriver == null) { return; } mobileDriver.quit(); mobileDriver = null; } }
问题原因
- 测试类中
startDriver()仅调用getMobileAppDriver()但未将新创建的driver实例传递给login、billPay等页面对象,导致这些页面对象持有已被销毁的旧driver引用(第一个测试用例执行完tearDown()后,driver被quit并置为null,但页面对象仍保留之前的引用)。 - 页面对象(如
LoginPage、BillPayPage)若为静态实例或初始化时绑定了固定driver,未在每次测试前更新引用,就会在第二个测试用例执行时使用已失效的driver发起操作,触发NoSuchSessionException。
解决办法
1. 测试类中更新页面对象的driver引用
修改@BeforeMethod方法,获取新driver实例后,重新初始化页面对象:
@BeforeMethod public void startDriver(){ AppiumDriver driver = DriverFactory.getMobileAppDriver(); // 每次测试前重新初始化页面对象,传入最新的driver login = new LoginPage(driver); billPay = new BillPayPage(driver); }
2. 页面对象采用实例化传参模式
确保页面对象不持有静态driver,而是在构造时传入driver实例,操作时使用该实例:
public class LoginPage { private final AppiumDriver driver; // 构造方法传入driver public LoginPage(AppiumDriver driver) { this.driver = driver; } public void enterPin(String pin) { // 使用当前实例的driver执行操作 driver.findElement(By.xpath("//*[@text='Enter PIN']")).sendKeys(pin); } }
3. 增加日志验证执行流程
在DriverFactory中添加日志,确认driver的创建和销毁流程是否符合预期:
public static AppiumDriver getMobileAppDriver(){ try{ if(mobileDriver != null){ logger.info("返回已存在的移动端Driver实例"); return mobileDriver; } logger.info("创建新的移动端Driver实例"); if (MobileProperties.getProperty("device.platform").equalsIgnoreCase("android")) { mobileDriver = MobileDriver.getAndroidDriver(); } else { mobileDriver = MobileDriver.getIOSDriver(); } } catch (Exception e){ logger.error("创建移动端Driver失败", e); e.printStackTrace(); } return mobileDriver; } public static void quitDriver() { if (mobileDriver == null) { logger.info("移动端Driver已为null,跳过销毁操作"); return; } logger.info("销毁移动端Driver实例"); mobileDriver.quit(); mobileDriver = null; }
4. 验证测试方法执行顺序
确认测试框架(如TestNG)的@BeforeMethod和@AfterMethod是否在每个测试用例前后正确执行,确保每个测试用例都使用独立的driver实例。
内容的提问来源于stack exchange,提问作者Chandan Dash
相关产品推荐
相关产品推荐

