-
Hi there! I want to know how can I use test database for testing fastapi app? When I repeat example code all my app is break. I think it happens because of double creation of the tables, once via migrations and other via app.state.database = test_database
client = TestClient(app)
@pytest.fixture(autouse=True, scope="session")
def create_test_database():
metadata.create_all(test_engine)
yield
metadata.drop_all(test_engine) I get this error while running tests: |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 10 replies
-
I depends if you are testing with client or without. If you do only unit/logic testing this should work: # fixture
@pytest.fixture(autouse=True, scope="module") # adjust your scope
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine) # i like to drop also before - even if test crash in the middle we start clean
metadata.create_all(engine)
yield
metadata.drop_all(engine)
# actual test - note to test async you need pytest-asyncio and mark test as asyncio
@pytest.mark.asyncio
async def test_actual_logic():
async with database: # <= note this is the same database that used in ormar Models
... (logic) If you want to test the actual app/api ( from fastapi import FastAPI
from starlette.testclient import TestClient
app = FastAPI()
# attach db to state
app.state.database = database
# define event like in production
@app.on_event("startup")
async def startup() -> None:
database_ = app.state.database
if not database_.is_connected:
await database_.connect()
@app.on_event("shutdown")
async def shutdown() -> None:
database_ = app.state.database
if database_.is_connected:
await database_.disconnect()
@pytest.fixture(scope="module")
def client():
client = TestClient(app)
yield client
# now the secret is that in order to trigger the events (and not have to manually connect the db)
# you have to use the client as context manager (so `with ...`).
def test_all_endpoints(): # note that with TestClient test is sync
with client as client: # this will connect/disconnect the db
... (logic) Note that db creation/drop is needed in both cases, but didn't want to repeat the same code for clarity, example fixture in first snippet. |
Beta Was this translation helpful? Give feedback.
-
I'll add another level of complexity: what if I want to run my tests in parallel, for example with the pytest-xdist plugin? Can I use the same database? Maybe if I wrap every test in a transaction there will be no race condition? What if a route called by the test client also starts a transaction? Do nested transaction work? What about FastAPI background tasks? At some point I think I should really use one unique database per test, but I'm having trouble mocking it in pytest. Should I mock it in |
Beta Was this translation helpful? Give feedback.
-
Building on this -- in local development I have a single postgres database. I want to use that database for running unit tests, as well as for holding local data as I develop. Is there a way to preserve my local data but also ensure I get a fresh database each time for a given unit test? Maybe using Here's my current setup which uses a SQLite in memory test db.
BTW: thanks for creating |
Beta Was this translation helpful? Give feedback.
-
In tests, use the
|
Beta Was this translation helpful? Give feedback.
-
This is really stale info before the major rework in version 0.20+. Could you please update the examples how to setup properly tests using ormar and pytest? @collerek P.S. Also would be really helpful to showcase usage of inmemory DB, because thats the most commonly used approach in test environment. |
Beta Was this translation helpful? Give feedback.
I depends if you are testing with client or without.
If you do only unit/logic testing this should work:
If you wa…