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
.
- 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. - 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 mockeddict
. 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.