烧瓶,烧瓶,sqlalchemy和pytest-selenium

时间:2017-08-18 21:08:52

标签: python selenium flask-sqlalchemy pytest flask-socketio

我正在尝试将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是应用程序的名称
  • 我正在使用以下PyPI包(以及其他):
    • 烧瓶== 0.12.2
    • 的SQLAlchemy == 1.1.13
    • 烧瓶的SQLAlchemy == 2.2
    • 烧瓶SocketIO == 2.9.2
    • 瓶脚本== 2.0.5
    • eventlet == 0.21.0
    • pytest == 3.2.1
    • pytest烧瓶== 0.10.0
    • pytest硒== 1.11.0

我已经为此应用程序运行了一个完整的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连接关闭的原因(或者从未打开过?)。我在灯具中加入了各种各样的数据库,但从来没有感觉到正确,也从未奏效过。

我迷失了,并希望任何指针都能找到解决方案。谢谢!

0 个答案:

没有答案