【问题标题】:Django StaticLiveServerTestCase sometimes ends with: An existing connection was forcibly closed by the remote hostDjango StaticLiveServerTestCase 有时以:远程主机强制关闭现有连接
【发布时间】:2023-03-31 13:43:01
【问题描述】:

在我新创建的 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:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 647, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 357, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 717, in __init__
    self.handle()
  File "C:\Users\pupeno\Temporary\untitled\venv\lib\site-packages\django\core\servers\basehttp.py", line 139, in handle
    self.raw_requestline = self.rfile.readline(65537)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socket.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:\Users\pupeno\Temporary\untitled\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm 2018.2.4\helpers\pycharm\django_test_manage.py" test foo.tests.TestImportCRMData C:\Users\pupeno\Temporary\untitled
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:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 647, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 357, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socketserver.py", line 717, in __init__
    self.handle()
  File "C:\Users\pupeno\Temporary\untitled\venv\lib\site-packages\django\core\servers\basehttp.py", line 139, in handle
    self.raw_requestline = self.rfile.readline(65537)
  File "C:\Users\pupeno\scoop\apps\python\current\lib\socket.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

【问题讨论】:

  • @DebanjanB:我不认为这是一个重复的问题。另一个是关于无法与 chromedriver 进行通信,而在我的情况下是有效的。错误发生在最后。
  • 这就是我得到的所有堆栈跟踪。它必须发生在一个单独的线程上。
  • 您能帮我确定您在哪一行看到错误吗?
  • 我的代码的任何一行都不会发生这种情况。我的测试都通过了,我只是不时将它发送给STDERR
  • 您找到解决方案了吗?

标签: python django selenium google-chrome selenium-chromedriver


【解决方案1】:

此错误消息...

ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host

...暗示 ChromeDriver 无法与 WebBrowsing 会话Chrome 浏览器 会话进行通信,因为它被远程主机。


您的主要问题是 webdriver.close()webdriver.quit()

形式的多次调用

根据最佳实践通过 Selenium 自动终止连接时,您应该始终在 tearDown(){} 方法中调用 driver.quit() 来关闭和销毁 WebDriver 和 Web 客户端 实例优雅。通过发送 "quit" 命令和 {"flags":["eForceQuit"]} 调用 quit() 方法 DELETEs 当前浏览会话,最后发送 /shutdown EndPoint 上的strong>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 : How to stop geckodriver process impacting PC memory, without calling driver.quit()?的详细讨论


更新 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,并且在执行以下行时会调用不匹配版本的 Google Chrome 二进制文件:

    cls.webdriver = webdriver.Chrome()
    

解决方案

确保:

  • Selenium 升级到当前级别 Version 3.141.59
  • ChromeDriver 已更新到当前的ChromeDriver v79.0.3945.36 级别。
  • Chrome 已更新至当前 Chrome 版本 79.0 级别。 (根据ChromeDriver v79.0 release notes
  • 清理你的项目工作区通过你的IDE重建你的项目只需要依赖。
  • 仅限 Windows 操作系统)使用 CCleaner 工具在执行您的测试套件之前和之后清除所有操作系统琐事。
  • 仅限 LinuxOSFree Up and Release the Unused/Cached Memory in Ubuntu/Linux Mint 在执行您的测试套件之前和之后。
  • 如果您的基本 Web 客户端 版本太旧,请卸载它并安装最新的 GA 和发布版本的 Web 客户端
  • 进行系统重启
  • 非root用户身份执行@Test
  • 始终在 tearDown(){} 方法中调用 driver.quit() 以优雅地关闭和销毁 WebDriverWeb Client 实例。

参考

您可以在以下位置找到一些相关讨论:

【讨论】:

  • 只有quit() 而没有close() 会导致同样的错误。我尝试了这两种方法的所有排列,但都没有错误。
  • @pupeno 我错过了你的步骤super().tearDownClass()。有必要吗?
  • 我添加它是因为这里的文档:docs.djangoproject.com/en/2.1/topics/testing/tools/…。这是被调用的代码:github.com/django/django/blob/…
  • 根据参考讨论,您只需调用一次 quit() 即可优雅地清除 webdriver 和 web 浏览器。任何额外的步骤都会引发异常。
  • 我用这些信息更新了问题。只需调用 quit() 就会引发相同的错误。查看回溯,我认为错误在 django 的服务器中,而不是在 selenium 中。
猜你喜欢
  • 2011-11-04
  • 2019-01-14
  • 2019-12-07
  • 2011-01-06
  • 2013-08-08
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
相关资源
最近更新 更多