我正在尝试将Selenium测试添加到Flask应用程序中,该应用程序严重依赖于Flask-SocketIO。但是,当从Selenium浏览器访问执行数据库查询的页面时,我在浏览器窗口中收到以下错误消息:
Traceback (most recent call last):
File "/home/bbbart/.virtualenvs/heistmanager/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 346, in connection
return self.__connection
AttributeError: 'Connection' object has no attribute '_Connection__connection'
During handling of the above exception, another exception occurred:
[...]
File "/home/bbbart/.virtualenvs/heistmanager/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 429, in _revalidate_connection
raise exc.ResourceClosedError("This Connection is closed")
sqlalchemy.exc.ResourceClosedError: This Connection is closed
bbbart
是我的用户名heistmanager
是应用程序的名称我已经为此应用程序运行了一个完整的pytest套件,包括依赖数据库的测试和使用pytest-flask的client
夹具进行的测试。只有在Selenium外部启动服务器时才会出现此错误。
为了让app正确启动并支持websockets我已经在conftest.py
中覆盖了python_flask中的LiveServer类和live_server fixture,如下所示(这是必要的吗?):
class LiveSocketIOServer(LiveServer):
"""The helper class to manage live socketio server. Handles creation and
stopping of the application in a separate process.
:param app: The application to run.
:param port: The port to run application.
"""
def start(self, socketio):
"""Start application in a separate process."""
def worker(app, port):
return socketio.run(app, port=port, use_reloader=False)
self._process = multiprocessing.Process(
target=worker,
args=(self.app, self.port)
)
self._process.start()
# We must wait for the server to start listening with a maximum
# timeout of 5 seconds.
timeout = 5
while timeout > 0:
time.sleep(1)
try:
urlopen(self.url())
timeout = 0
except BaseException:
timeout -= 1
def __repr__(self):
return '<LiveSocketIOServer listening at %s>' % self.url()
和
@pytest.yield_fixture(scope='function')
def live_server(request, app, monkeypatch):
"""Run application in a separate process.
When the ``live_server`` fixture is applied, the ``url_for`` function
works as expected::
def test_server_is_up_and_running(live_server):
index_url = url_for('index', _external=True)
assert index_url == 'http://localhost:5000/'
res = urllib2.urlopen(index_url)
assert res.code == 200
"""
# Find an open port
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 0))
port = sock.getsockname()[1]
sock.close()
server_name = app.config['SERVER_NAME'] or 'localhost'
monkeypatch.setitem(app.config, 'SERVER_NAME',
_rewrite_server_name(server_name, str(port)))
server = LiveSocketIOServer(app, port)
if request.config.getvalue('start_live_server'):
server.start(SOCKETIO)
yield server
server.stop()
我的测试看起来像这样:
@pytest.mark.usefixtures('live_server')
class TestSockets:
"""Tests for socket.io (with selenium)."""
@pytest.mark.nondestructive
def test_admin_login(self, config, selenium):
selenium.get(url_for('main.index', _external=True))
assert 'Hello stranger!' in selenium.page_source
selenium.find_element_by_link_text('Log in to administer').click()
assert '<h1>Login</h1>' in selenium.page_source
selenium.find_element_by_name('username').send_keys(
config['USERNAME_ADMIN'])
selenium.find_element_by_name('password').send_keys('*******')
selenium.find_element_by_name('submit').click()
assert 'Logged in as %s' % config['USERNAME_ADMIN'] in selenium.page_source
(您可能会识别Miguel Grinberg's excellent Flasky demo中的一些元素。: - ))
在测试的倒数第二行中进行第二次click
调用后,会出现上述错误。这随后当然会使assert
语句失败,但这不是重点。
测试从烧瓶脚本管理器命令运行:
APP = create_app(os.getenv('HEIST_CONFIG') or 'default')
MANAGER = Manager(APP)
@MANAGER.command
def test():
"""Run the tests."""
import pytest
pytest.main(['--driver', 'Chrome',
os.path.join(basedir, 'tests')])
我花了几个小时试图找出SQLAlchemy连接关闭的原因(或者从未打开过?)。我在灯具中加入了各种各样的数据库,但从来没有感觉到正确,也从未奏效过。
我迷失了,并希望任何指针都能找到解决方案。谢谢!