I can mock a context manager for a sqlalchemy session with:
@patch("app.path_to_code.Session")
def test_get_users_to_query(self, mock_session) -> None:
self.engine = create_engine("sqlite:///:memory:")
self.session = Session(self.engine)
mock_session.return_value.__enter__=Mock(return_value=self.session)
mock_session.__exit__ = Mock(return_value=None)
Base.metadata.create_all(self.engine)
fake_user1 = User(
display_name="Jane Doe", user_name="jdb2", query=False
)
fake_user2 = User(
display_name="John Doe", user_name="jdb", query=True
)
with mock_session() as session:
session.add(fake_user)
session.commit()
users = get_users_to_query()
where get_users_to_query is defined in eg app.path_to_code.py
This works fine. But if I want a factory method to return the patched mock session:
def sqlalchemy_mock_get_factory(self, session_to_patch: str) -> Callable:
self.engine = create_engine("sqlite:///:memory:")
self.session = Session(self.engine)
def patcher():
mock_session = patch(session_to_patch)
mock_session.return_value.__enter__ = Mock(return_value=self.session)
mock_session.__exit__ = Mock(return_value=None)
return mock_session
Base.metadata.create_all(self.engine)
return patcher
And then use it like:
mock_session_patcher = self.sqlalchemy_mock_get_factory(
session_to_patch="app.path_to_code.Session"
)
with mock_session_patcher() as session:
fake_user1 = User(
display_name="Jane Doe", user_name="jdb2", query=False
)
fake_user2 = User(
display_name="John Doe", user_name="jdb", query=True
)
session.add(fake_user1)
session.commit()
users_to_query = get_users_to_query()
I get an AttributeError: '_patch' object has no attribute 'return_value'
The type of the mock_session in the first case is MagicMock
and the session returned by with mock_session
is 'sqlalchemy.orm.session.Session'
whereas in the second case with the factory the mocked_session_patcher
is of type unittest.mock._patch
.
If i mock the enter in patcher with:
def patcher():
mock_session = patch(session_to_patch)
mock_session.__enter__ = Mock(
return_value=self.session
)
mock_session.__exit__ = Mock(return_value=None)
return mock_session
The session the query gets run against is the production DB, and not the mocked session I have tried to patch - so the patch hasnt worked.
Can anyone explain why this is and suggest a fix?