我对为什么在一个测试版本而不是另一个测试版本中更新数据库(和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用法。