在我刚创建的Django应用程序中,我将其更改为使用PostgreSQL,并创建了一个应用程序,我有以下测试:
from django.contrib.auth.models import User
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class TestWebBrowser(StaticLiveServerTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.webdriver = webdriver.Chrome()
cls.webdriver.implicitly_wait(10)
@classmethod
def tearDownClass(cls):
cls.webdriver.close()
cls.webdriver.quit()
super().tearDownClass()
def setUp(self):
self.admin = User.objects.create_superuser(username="username", password="password",
email="example@example.com")
def test_log_in(self):
self.webdriver.get(f"{self.live_server_url}/admin")
self.webdriver.find_element_by_id("id_username").send_keys("username")
self.webdriver.find_element_by_id("id_password").send_keys("password")
self.webdriver.find_element_by_id("id_password").send_keys(Keys.RETURN)
self.webdriver.find_element_by_link_text("Users").click()
测试总是运行,Chrome启动,按照测试的要求进行,但在最后,有时会抛出以下错误:
Exception happened during processing of request from ('127.0.0.1', 55283)
Traceback (most recent call last):
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 647, in process_request_thread
self.finish_request(request, client_address)
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 717, in __init__
self.handle()
File "C:UserspupenoTemporaryuntitledvenvlibsite-packagesdjangocoreserversbasehttp.py", line 139, in handle
self.raw_requestline = self.rfile.readline(65537)
File "C:Userspupenoscoopappspythoncurrentlibsocket.py", line 589, in readinto
return self._sock.recv_into(b)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
所有测试都通过了。我只是把它拿到STDERR
。有什么想法吗?我是不是错过了一些撕扯?
如果我将tearDownClass
更改为:
@classmethod
def tearDownClass(cls):
cls.webdriver.quit()
我在相同的频率下得到了相同的误差(据我所能观察到的,没有测量过(。
我正在运行:
Django==2.1.2
selenium==3.141.0
和
> chromedriver.exe --version
ChromeDriver 2.43.600210 (68dcf5eebde37173d4027fa8635e332711d2874a)
和
Google Chrome Version 70.0.3538.102 (Official Build) (64-bit)
运行测试的完整输出如下所示:
Testing started at 15:33 ...
C:UserspupenoTemporaryuntitledvenvScriptspython.exe "C:Program FilesJetBrainsPyCharm 2018.2.4helperspycharmdjango_test_manage.py" test foo.tests.TestImportCRMData C:UserspupenoTemporaryuntitled
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 49825)
Traceback (most recent call last):
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 647, in process_request_thread
self.finish_request(request, client_address)
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "C:Userspupenoscoopappspythoncurrentlibsocketserver.py", line 717, in __init__
self.handle()
File "C:UserspupenoTemporaryuntitledvenvlibsite-packagesdjangocoreserversbasehttp.py", line 139, in handle
self.raw_requestline = self.rfile.readline(65537)
File "C:Userspupenoscoopappspythoncurrentlibsocket.py", line 589, in readinto
return self._sock.recv_into(b)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
----------------------------------------
Destroying test database for alias 'default'...
Process finished with exit code 0
此错误消息。。。
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
意味着ChromeDriver无法与网络浏览会话通信,即Chrome浏览器会话,因为它被远程主机强制关闭。
您的主要问题是webdriver.close()
和webdriver.quit()
形式的多次调用
当根据最佳实践通过Selenium自动终止连接时,您应该始终调用tearDown(){}
方法中的driver.quit()
来关闭&优雅地销毁WebDriver和Web客户端实例。调用quit()
方法DELETE
通过发送带有{"flags":["eForceQuit"]}的"quit">命令来启动当前浏览会话,并最终在/shutdownEndPoint
上发送GET请求。下面是一个例子:
1503397488598 webdriver::server DEBUG -> DELETE /session/8e457516-3335-4d3b-9140-53fb52aa8b74
1503397488607 geckodriver::marionette TRACE -> 37:[0,4,"quit",{"flags":["eForceQuit"]}]
1503397488821 webdriver::server DEBUG -> GET /shutdown
因此,在调用quit()
方法时,Web Browser
会话和WebDriver
实例将被完全杀死。因此,您不必包含任何额外的步骤(调用close()
(,这将是主流标准的开销。
解决方案
首先,您删除以下行:
cls.webdriver.close()
下一行:
cls.webdriver.quit()
必然会以最佳方式终止连接。
在这里,您可以找到关于Selenium的详细讨论:如何在不调用driver.quit((的情况下阻止geckodriver进程影响PC内存?
更新A
根据liveservertestcase,tearDownClass()
@classmethod定义为:
@classmethod
def tearDownClass(cls):
cls.selenium.quit()
super().tearDownClass()
根据django/django/test/testcases.py,这被称为:
@classmethod
def tearDownClass(cls):
cls._tearDownClassInternal()
cls._live_server_modified_settings.disable()
super().tearDownClass()
更新B
虽然你提到过:
- 使用ChromeDriver 2.43.600210
- 使用Google Chrome版本70.0.3538.102
根据ChromeDriver v2.43:的发行说明
支持Chrome v69-71
因此它们是兼容的,但您的机器中可能安装了多个Google Chrome,并且当执行以下行时会调用不匹配的GoogleChromebinary版本:
cls.webdriver = webdriver.Chrome()
解决方案
确保:
- 硒升级到当前版本3.141.59
- ChromeDriver更新为当前ChromeDriverv79.0.3945.36版本
- Chrome更新到当前Chrome 79.0版本。(根据ChromeDriver v79.0发布说明(
- 通过IDE清理您的项目工作区,并仅使用所需的依赖项重建项目
- (仅限WindowsOS(使用CCleaner工具,在执行测试套件前后清除所有操作系统杂务
- (仅限LinuxOS(在执行测试套件之前和之后,释放Ubuntu/Linux Mint中未使用的/缓存的内存
- 如果您的基本Web客户端版本太旧,请将其卸载并安装最新的GA和发布的Web客户端版本
- 进行系统重新启动
- 以非root用户身份执行您的
@Test
- 总是调用CCD_ 17方法中的CCD_;优雅地销毁WebDriver和Web客户端实例
参考
你可以在中找到一些相关的讨论
- urlib3.exceptions.ProtocolError:("连接中止。",error(10054,"远程主机强制关闭了现有连接"(