How to mock dependencies? #1789
-
SummaryCan you please add a dependency override to the application. Something similar to fastapi's app.dependency_overrides. Basic Example@pytest.fixture
def client(app):
database = TestAsyncSessionLocal()
def test_get_db(app):
try:
yield database
finally:
database.close()
app.dependency_overrides['db'] = Provide(test_get_db) # nothing like dependency_overrides in starlite
... Drawbacks and ImpactHere's what I tried: def client(app):
database = TestAsyncSessionLocal()
def test_get_db(app):
try:
yield database
finally:
database.close()
app.dependencies['db'] = Provide(test_get_db)
... This doesn't work because handlers are already registered in main:app. So overriding dependencies like this after handlers have been registered changes nothing. Unresolved questionsNo response |
Beta Was this translation helpful? Give feedback.
Replies: 8 comments 3 replies
-
Hi. It's basically already in place. The For controllers you can use attribute mocking. What's missing? |
Beta Was this translation helpful? Give feedback.
-
Thanks for your reply. But the create_test_client was built upon TestClient, and I want to use AsyncTestClient. |
Beta Was this translation helpful? Give feedback.
-
Expanding on what @Goldziher said: It's unlikely that we'll support this for a number of reasons (which we actually cover here in our FastAPI migration guide). The gist is that it's not actually needed and often a crude workaround that has more drawbacks than benefits. Overriding dependencies in such a way:
The solution to your problem is this: @pytest.fixture
def database():
database = TestAsyncSessionLocal()
try:
yield database
finally:
database.close()
@pytest.fixture
def client(app, mocker, database):
mocker.patch("path.to.get_db", return_value=database) This actually has several benefits:
If you do need to actually swap out the whole dependency function because you're performing some additional logic in there you can easily adapt this pattern: def get_database(app):
database = TestAsyncSessionLocal()
try:
yield database
finally:
database.close()
@pytest.fixture
def client(app, mocker, database):
mocker.patch("path.to.get_db", new=get_database) Just to illustrate what the proper way to override dependencies like you want would look like in contrast: # add a separate fixture for the database to ensure it's always closed
# no matter where errors might occur
@pytest.fixture
def database()
database = TestAsyncSessionLocal()
try:
yield database
finally:
if database.is_open:
database.close()
@pytest.fixture
def client(app, database):
def test_get_db(app):
try:
yield database
finally:
database.close()
try:
app.dependency_overrides['db'] = Provide(test_get_db)
finally:
app.dependency_overrides = {} # ensure to reset overrides at the end |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Thanks for your reply. I tried your solution using mock, but it doesn't work. The test still seems to be using my original db instead of the test_db. Here's how my app looks in the main.py:
Please help |
Beta Was this translation helpful? Give feedback.
-
Can you provide an example of your app, the |
Beta Was this translation helpful? Give feedback.
-
app.main.py
app.api.tests.conftest.py
app.core.database.py
Thank you. |
Beta Was this translation helpful? Give feedback.
-
the solution here explains quite well the reasonning, still the test fails for mainly 2 reasons: the
using a context manager to patch should be preferred. see the diff here from a non-passing test to a passing one: euri10/mock_dependency_litestar@9434736 |
Beta Was this translation helpful? Give feedback.
A couple of things here, but let me just say that this isn't something Litestar specific but rather about how scopes, imports and mocking works.
create_app
function and then immediately calling it in the same file is functionally equivalent to simply creating the app in the file directly.app
. This will also set the dependencies on that objectapp.core.database.get_db
. Since the application object has already been created, this will not change theget_db
function you passed to itTo fix it you can either:
get_db
…