使用Python unittest执行Selenium用例时出现no such session错误求解决
解决unittest + Selenium 遇到的「no such session」错误
嗨,我来帮你排查并解决这个问题。先拆解下问题根源,再给你两种可行的修复方案:
问题根源拆解
你的代码触发这个错误,核心是没摸透unittest框架的执行逻辑:
- 每个
test_开头的方法都是独立测试用例:unittest会把所有以test_命名的方法当作单独的测试用例执行,而且每个用例执行完毕后都会调用tearDown()方法。你的test_globe执行完后,tearDown()直接关闭了浏览器driver,后面的test_login、test_home再调用driver时,会话已经不存在了。 - 全局变量
driver的误用:用global管理WebDriver实例完全不适合unittest,因为每个测试用例的实例是相互隔离的,而且测试方法的执行顺序不一定是你写的顺序(unittest默认按方法名的ASCII码排序),搞不好test_login会先于test_globe执行,直接导致driver未初始化就报错。 - 初始化方法用错了地方:把driver的初始化放在
test_globe这个测试方法里不合理,unittest专门提供了setUp()(每个用例执行前跑一次)和setUpClass()(整个测试类只跑一次)来做初始化操作。
修复方案
方案1:每个测试用例用独立的浏览器实例
适合测试用例之间没有依赖的场景,每个用例都会打开新浏览器,执行完就关闭:
import unittest from selenium import webdriver from selenium.webdriver.common.keys import Keys class KenLogin(unittest.TestCase): def setUp(self): # 每个测试用例执行前初始化driver self.driver = webdriver.Chrome(executable_path='E:\Learning\chromedriver.exe') self.driver.maximize_window() self.driver.implicitly_wait(10) # 注意:这里参数是秒!你之前写2000是2000秒,这明显不对 def test_login(self): self.driver.get("http://qa.kenzen.com") username = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[1]/input") password = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[2]/input") username.send_keys("pardeepk@clovity.com") password.send_keys("Kenzen@123") button = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/button") button.send_keys(Keys.ENTER) print("Login Pass") def test_home(self): # 因为是独立实例,所以需要先完成登录操作 self.driver.get("http://qa.kenzen.com") # 复用登录代码 username = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[1]/input") password = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[2]/input") username.send_keys("pardeepk@clovity.com") password.send_keys("Kenzen@123") self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/button").send_keys(Keys.ENTER) teamsummary = self.driver.find_element_by_id("teamsummary") teamsummary.click() print("Home Pass") def test_newteam(self): # 同样需要先登录 self.driver.get("http://qa.kenzen.com") username = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[1]/input") password = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[2]/input") username.send_keys("pardeepk@clovity.com") password.send_keys("Kenzen@123") self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/button").send_keys(Keys.ENTER) addteam = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[1]/ul[2]/li/button") addteam.click() teamname = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[2]/div/div[1]/input") admin = self.driver.find_element_by_id("administrator") admin.send_keys("qa@kenzen.com,qa1@kenzen.com") addteambutton = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[2]/div/div[6]/button") addteambutton.click() print("Team Added") def tearDown(self): # 每个用例执行后关闭浏览器,quit()比close()更彻底,会销毁整个会话 self.driver.quit() if __name__ == "__main__": unittest.main()
方案2:所有测试用例共享同一个浏览器实例
如果你的测试用例是有依赖顺序的(比如必须先登录,再操作首页,再创建团队),用这个方案,整个测试类只初始化一次浏览器:
import unittest from selenium import webdriver from selenium.webdriver.common.keys import Keys class KenLogin(unittest.TestCase): @classmethod def setUpClass(cls): # 整个测试类执行前只初始化一次driver cls.driver = webdriver.Chrome(executable_path='E:\Learning\chromedriver.exe') cls.driver.maximize_window() cls.driver.implicitly_wait(10) # 修正为秒级参数 def test_login(self): self.driver.get("http://qa.kenzen.com") username = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[1]/input") password = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/div[2]/input") username.send_keys("pardeepk@clovity.com") password.send_keys("Kenzen@123") button = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/form/button") button.send_keys(Keys.ENTER) print("Login Pass") def test_home(self): # 直接复用之前的登录会话 teamsummary = self.driver.find_element_by_id("teamsummary") teamsummary.click() print("Home Pass") def test_newteam(self): # 继续复用会话 addteam = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[1]/ul[2]/li/button") addteam.click() teamname = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[2]/div/div[1]/input") admin = self.driver.find_element_by_id("administrator") admin.send_keys("qa@kenzen.com,qa1@kenzen.com") addteambutton = self.driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/div[2]/div/div[6]/button") addteambutton.click() print("Team Added") @classmethod def tearDownClass(cls): # 整个测试类执行完后再关闭浏览器 cls.driver.quit() if __name__ == "__main__": unittest.main()
额外要注意的细节
implicitly_wait的参数:你之前写的2000是错误的,这个方法接收的是秒数,不是毫秒!2000秒等于30多分钟,会导致测试无意义地等待很久,改成10秒左右就合适。- 测试方法的执行顺序:unittest默认会按方法名的ASCII码排序执行,如果你需要严格按登录→首页→创建团队的顺序执行,可以把方法名改成
test_01_login、test_02_home、test_03_newteam,或者用第三方库unittest-ordering来指定顺序。 - 尽量不用全局变量:在unittest里,用实例变量(
self.driver)或类变量(cls.driver)管理WebDriver是更规范的做法,能避免会话混乱的问题。
内容的提问来源于stack exchange,提问作者Pardeep Kochhar
相关产品推荐
相关产品推荐

