-1

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?

abinitio
  • 609
  • 6
  • 20

0 Answers0