2017-09-24 30 views
0

我有一個使用SQLAlchemy的Web應用程序。在生產中支持它的數據庫是Postgres,但爲了進行單元測試,我還希望能夠對SQLite進行初始化。如何選擇性地初始化模塊級別的對象?

我使用alembic進行數據庫模式更改。出於這個原因,我決定不支持SQLite進行生產,因爲讓alembic支持SQLite比我想要的更麻煩。但是,我仍然希望能夠在SQLite內部從頭開始創建表,以便進行測試;這不會調用alembic,而只是使用SQLAlchemy的create_all()

我使用的聲明性模型,併爲了使蒸餾器更好地工作,我給自己定的約束的命名約定作爲其文檔中建議:

naming = { 
    "ix": 'ix_%(column_0_label)s', 
    "uq": "uq_%(table_name)s_%(column_0_name)s", 
    "ck": "ck_%(table_name)s_%(constraint_name)s", 
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", 
    "pk": "pk_%(table_name)s", 
} 

Base = declarative_base(metadata=MetaData(naming_convention=naming)) 

class Model1(Base): 
    ... 

這正常的Postgres裏面,但沒有在SQLite中;顯然這個命名約定在某種程度上是不兼容的。 (這可能與這樣的事實,我的一些機型有Boolean列,這顯然在這兩個引擎的處理不同。)

因爲我實際上並不需要SQLite的生產,不能使用蒸餾器,如果有我做了,我傾向於在這種情況下簡單地放棄命名約定,並在運行測試時讓它使用默認名稱。但是,因爲這一切都是在模塊頂層完成的(並且必須是,爲了使用Base作爲基類),我無法找到一種方法來進行區分。理想情況下,我可以在導入模型之前在測試套件中設置某種標誌,這會導致該模塊使用默認元數據創建Base,而不是啓用命名約定。但我無法在進口時找到一種方法來進行這種溝通。

如何在導入時傳遞數據來控制聲明基的創建?或者,有沒有一種方法可以輕鬆使SQLite在啓用命名約定的情況下工作?

+2

如何使用配置文件? – georgexsh

+0

可能。理想情況下,我不必在運行單元測試和運行完整的開發服務器之間手動更改文件,但我總是可以讓測試套件寫出文件或其他內容。 –

+1

你也可能檢測到代碼正在運行,例如pytest,請檢查'PYTEST_CURRENT_TEST'環境:https://docs.pytest.org/en/latest/example/simple.html#pytest-current-test-environment -variable – georgexsh

回答

0

我最終通過環境變量解決了這個問題。在項目模塊:

if os.environ.get('MYPROJECT_TESTING') == '1': 
    Base = declarative_base() 
else: 
    Base = declarative_base(metadata=MetaData(naming_convention=naming) 

然後在測試工具:

os.environ['MYPROJECT_TESTING'] = '1' 
import myproject 

這工作得很好,但你必須確保不留下一個shell環境MYPROJECT_TESTING設置,或者曾經將其設置在一般而言,除了在測試腳本中自動執行。