[QUESTION] How can I populate data in a test database using the yield session functionality with pytest?
See original GitHub issueDescription
How can I populate data in a test database dynamically using the yield session functionality with pytest? What are best practices in FastAPI testing? Is there a good example I could follow?
Additional context
I am getting this error:
AttributeError: 'Depends' object has no attribute 'add'
I have 2 files as an example
test_apps.py
import pytest
from fastapi import Depends
from app.main import app
from config import Config
from data_init import APP
from models.models import AppModel
from test_base import client, get_test_db
from sqlalchemy.orm import Session
@pytest.fixture(scope="session", autouse=True)
def init(db: Session=Depends(get_test_db)):
new_app = AppModel(**APP)
db.add(new_app)
db.commit()
db.refresh(new_app)
AppModel.filter_or_404(db, id=APP["id"])
def test_get_apps(client, db: Session=Depends(get_test_db)):
response = client.get("/applications")
assert response.status_code == 200
test_base.py
from typing import Optional, AsyncIterable
import pytest
from fastapi import Depends
from starlette.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.engine import Engine as Database
from sqlalchemy.orm import Session
from sqlalchemy_utils import database_exists, create_database, drop_database
from app.main import app
from app.dependency import get_db
from models.__base import Base
from config import Config
url = str(Config.SQLALCHEMY_DATABASE_URI + "_test")
_db_conn = create_engine(url)
def get_test_db_conn() -> Database:
assert _db_conn is not None
return _db_conn
def get_test_db(db_conn=Depends(get_test_db_conn)) -> AsyncIterable[Session]:
sess = Session(bind=db_conn)
try:
yield sess
finally:
sess.close()
@pytest.fixture(scope="session", autouse=True)
def create_test_database():
"""
Create a clean database on every test case.
For safety, we should abort if a database already exists.
We use the `sqlalchemy_utils` package here for a few helpers in consistently
creating and dropping the database.
"""
try:
assert not database_exists(url), "Test database already exists. Aborting tests."
create_database(url) # Create the test database.
Base.metadata.create_all(_db_conn) # Create the tables.
app.dependency_overrides[get_db] = get_test_db # Mock the Dependency
yield # Run the tests.
finally:
drop_database(url) # Drop the test database.
@pytest.fixture()
def client():
"""
When using the 'client' fixture in test cases, we'll get full database
rollbacks between test cases:
"""
with TestClient(app) as client:
yield client
Is there a better way or a better practice to handle testing?
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (5 by maintainers)
Top Results From Across the Web
Populate your Django test database with pytest fixtures - FlowFX
I'm working on a side project that uses data from an external API. For performance reasons I store this data in a local...
Read more >How to set up and tear down a database between tests in ...
For each test that has test_db in its argument list pytest first runs Base.metadata.create_all(bind=engine) , then yields to the test code, ...
Read more >Effective Python Testing With Pytest
In this tutorial, you'll learn how to take your testing to the next level with pytest. You'll cover intermediate and advanced pytest ......
Read more >Fun with Fixtures for Database Applications | by Geoffrey Koh
We use one fixture to setup the database, and another to insert the test data. Within the core functions, it is a good...
Read more >pytest fixtures: explicit, modular, scalable
These are accessed by test functions through arguments; for each fixture ... to re-use fixtures across function, class, module or whole test session...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thank you for pointing me to the right direction @dmontagu
I got it working like this:
test_base.py
test_app.py
I am a little confused why
create_test_database
needs to be imported but never used anywhere. But that will do for now. Thanks !You need to import it otherwise pytest won’t know it exists, and won’t be able to find it while looking for autouse fixtures.
If you place the autouse fixture in a file called
conftest.py
that is in the same folder or a parent folder, it will be automatically detected and imported by pytest (conftest.py
is like pytest’s version of__init__.py
). Typically it makes sense to put anyautouse=True
fixtures in aconftest.py
to make sure they get used without needing to import anyting.