0

I've read some answers on this website which talk about mocking SQLAlchemy objects using dictionaries. Such as this. However, I want to not have a dictionary, but an actual SQLALchemy Table object instantiated.

Let me explain with sample code.

This is the User table (I've shown only 2 columns but there are others)

User = Table(
    "User",
    Base.metadata,
    Column(
        "id",
        BigInteger,
        primary_key=True,
        autoincrement=True,
    ),
    Column("name", String(length=100), nullable=False),
)

This is the function that I'm testing

async def fetch_users(self, conn: AsyncConnection) -> User:
    results = await conn.execute(select(User))
    return results.all()

This function is called in a controller and there are other service/repository classes in that flow, but to explain how the return value of the above function is used, it's kind of like this in user_service.py.

users = await user_repository.fetch_users(conn=conn)
for user in users:
    json_response["owner"] = user.name
    json_response["id"] = user.id
    .
    .
    .
    some other attributes of the `User` table

Now, I have a test case written for the controller like so

app = FastAPI()
@pytest_asyncio.fixture()
def client():
    with TestClient(app=app) as c:
        yield c

class TestUser:
    USER_FETCH_URL = "/users"

    @pytest.mark.asyncio
    @patch("repositories.users.UserRepository.fetch_users")
    async def test_fetch_users(self, mock_fetch_users, client):
        mock_fetch_users.return_value = ???

        response = client.get(self.USER_FETCH_URL)
        assert response.status_code == 200

I don't know what the return_value of mock_fetch_users should be. When I do User(id=11, name="David"), it throws an error - TypeError: 'Table' object is not callable.

  1. I know I can put a dictionary for the return_value, like {"name": "David", "id": 11}, but my service layer code which accesses by .id and .name will fail when it's called by the test case.
  2. I also know that I can change the service layer code to access by square brackets. Square brackets will work for the SQLAlchemy Row object (i.e., when the function is called in the usual flow for customers), as well as when I am running my test case using a mocked dict. So, user_service.py will now have
for user in users:
    json_response["owner"] = user["name"]
    json_response["id"] = user["id"]
    .
    .
    .
    some other attributes of the `User` table

But this is not very readable. I'd prefer to have the .id format instead.

So, I wanted to know if there's any way I can mock/instantiate a Row object with dummy data or something. My purpose is to make the service class function work for both normal API calls triggered by customers as well as the test cases I've written, while also retaining readability of the format.

Sidharth Samant
  • 714
  • 8
  • 28

0 Answers0