How can I use pydanic BaseModel json method to generate json data for my test request?
For example I have a endpoint that accepts a Action(BaseModel) and for testing it I want to create a object of Action and use .json then pass it to client.post(json=action.json).
request = DoActionRequest(
game_id=self.game.id,
action=Action(
action_type=Action.ActionType.CAPTAIN_CALL_FOR_AN_ATTACK
),
payload=None
)
headers = auth_header_generator(self.game.get_fd_caption())
response = self.client.post(
self.url, json=request.json(), headers=headers
)
This gives me 422 http status code. but when I use the value of request.json() like
{"game_id": "1", "action": {"action_type": "call for an attack", "action_data": null}, "payload": null}
It works fine.
@Glyphack
I think request.json() returns str. But, the test client accepts dict.
Would you try request.dict()?
https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
https://fastapi.tiangolo.com/tutorial/testing/
I tried to pass requset.dict() for field json and got error Action object is not json serializable. I guess this happens because I have to nested messages And when I call .dict Only first one gets serialized to dict. Maybe one way is to use .dict on every class but this breaks the typing.
then I passed request.dict() to data field and it worked without error but the response had 400 status code with detail:
{'detail': 'There was an error parsing the body'}
But I found a way to make it working by using json.dumps the request.dict() and fill json filed with it.
@Glyphack
I guess json.dumps can't serialize nested Enum.
You should give a serialized request to data.
response = client.post("/", data=request.json())
I imagine your request model. This sample is a simple way.
from enum import Enum
from pydantic import BaseModel
from fastapi import FastAPI
from starlette.testclient import TestClient
class Action(BaseModel):
class ActionType(Enum):
CAPTAIN_CALL_FOR_AN_ATTACK = 'call for an attack'
action_type: ActionType
action_data: str = None
class DoActionRequest(BaseModel):
game_id: str
action: Action
payload: str
app = FastAPI()
@app.post("/")
async def read_main(body: DoActionRequest):
return body
def test_read_main():
client = TestClient(app)
request = DoActionRequest(
game_id='123',
action=Action(
action_type=Action.ActionType.CAPTAIN_CALL_FOR_AN_ATTACK
),
payload='456'
)
response = client.post("/", data=request.json())
assert response.status_code == 200
assert response.json() == {
'game_id': '123',
'action': {'action_type': 'call for an attack', 'action_data': None},
'payload': '456'
}
if __name__ == '__main__':
test_read_main()
Hey @koxudaxi It's working in this way thank you. I'll close this issue.
Thanks @koxudaxi for your help here! :bowing_man:
Thanks @Glyphack for reporting back and closing the issue.
Most helpful comment
Thanks @koxudaxi for your help here! :bowing_man:
Thanks @Glyphack for reporting back and closing the issue.