令人困惑的SQLAlchemy行为;对象是否连接到Session取决于test_client请求

时间:2019-06-04 20:22:04

标签: python flask sqlalchemy flask-sqlalchemy

我对为什么在一个测试版本而不是另一个测试版本中更新数据库(和session.commit())之后为什么不更新SQLAlchemy中的加载对象感到困惑。在工作版本中,引用的对象仍仍附加到会话,但在非工作版本中具有Session.object_session(object) == None。我正在使用pytest固定装置来设置会话和应用环境,并使用了clean_*个版本,因为这些固定装置的某些版本也期望数据库也不为空。这是代码(首先是上下文的夹具,然后是工作和非工作测试)

灯具:

@pytest.fixture(scope="session")
def postgresql(request, logger):
    p = testing.postgresql.Postgresql()
    logger.debug(p.url())

    def fin():
        logger.debug("teardown DB")
        p.stop()

    request.addfinalizer(fin)

    return p

@pytest.fixture()
def clean_app(request, clean_postgresql):

    test_config = TestConfig()
    test_config.SQLALCHEMY_DATABASE_URI = clean_postgresql.url()

    app = create_app(test_config, settings_override={
        "SQLALCHEMY_DATABASE_URI": clean_postgresql.url(),
        "TOKEN_SECRET_KEY": "secret"
    })
    ctx = app.app_context()
    ctx.push()
    app.db = db
    db.create_all()

    def fin():
        ctx.pop()

    request.addfinalizer(fin)
    return app


@pytest.fixture()
def clean_session(app, request):
    connection = app.db.engine.connect()
    transaction = connection.begin()
    options = dict(bind=connection, binds={})
    session = app.db.create_scoped_session(options=options)

    original_session = app.db.session
    app.db.session = session

    def fin():
        transaction.rollback()
        session.remove()
        app.db.session = original_session

    request.addfinalizer(fin)
    return session


@pytest.fixture()
def clean_client(clean_app):
    client = clean_app.test_client()

    yield client

@pytest.fixture()
def make_foo():
  """Factory to make a foo object for tests"""
  def _make_foo(params={}):
    foo_params = dict(FOO_DEFAULTS, **params)
    return Foo.create(foo_params)
  yield _make_user

注释掉带有工作示例的测试(Foo类与Bar类具有一对多关系):

def test_example(request, clean_app, clean_session, clean_client, make_object):
  foo = make_foo()
  foo.create_new_bar()
  assert len(foo.bars) == 1 #True
  response = clean_client.put(
      "/api/foos/{1}?action=create_bar".format(foo.id),
      headers={'Authorization': 'Bearer <Valid Token>'},
      json={'barAttribute': 18},
      # data=json.dumps({'barAttribute': 18}),
      # content_type='application/json'
  )
  assert response.status == 200 #True
  print(Session.object_session(foo)) #This prints `None` with current code
  assert len(foo.bars) == 2 #This fails with 1 != 2 with current code

如果我注释掉json=行并取消注释下面的两行,代码将起作用,并且Session.object_session(foo)将按预期打印出sqlalchemy.orm.session.SignallingSession对象。

我显然不完全了解某处的SQLAlchemy Session用法。

0 个答案:

没有答案