1

I'm trying to implement testing my post route. It works in my project. I have problems only with pytest.

main.py:

@app.post('/create_service', status_code=status.HTTP_201_CREATED)
async def post_service(
    response: Response, service: CreateService, db: Session = Depends(get_db)
):
    service_model = models.Service()
    service_name = service.name
    service_instance = db.query(models.Service).filter(
        models.Service.name == service_name
    ).first()
    if service_instance is None:
        service_model.name = service_name
        db.add(service_model)
        db.commit()
    serviceversion_model = models.ServiceVersion()
    service_instance = db.query(models.Service).filter(
        models.Service.name == service_name
    ).first()
    serviceversion_instance = db.query(models.ServiceVersion).filter(
        models.ServiceVersion.service_id == service_instance.id
    ).filter(models.ServiceVersion.version == service.version).first()
    if serviceversion_instance:
        raise HTTPException(
            status_code=400, detail='Version of service already exists'
        )
    serviceversion_model.version = service.version
    serviceversion_model.is_used = service.is_used
    serviceversion_model.service_id = service_instance.id
    db.add(serviceversion_model)
    db.commit()
    db.refresh(serviceversion_model)
    service_dict = service.dict()
    for key in list(service_dict):
        if isinstance(service_dict[key], list):
            sub_dicts = service_dict[key]
    if not sub_dicts:
        response.status_code = status.HTTP_400_BAD_REQUEST
        return HTTPException(status_code=400, detail='No keys in config')

    servicekey_models = []
    for i in range(len(sub_dicts)):
        servicekey_model = models.ServiceKey()
        servicekey_models.append(servicekey_model)
        servicekey_models[i].service_id = service_instance.id
        servicekey_models[i].version_id = serviceversion_model.id
        servicekey_models[i].service_key = sub_dicts[i].get('service_key')
        servicekey_models[i].service_value = sub_dicts[i].get('service_value')
        db.add(servicekey_models[i])
        db.commit()
    return 'created'

test_main.py:

def test_create_service(client, db: Session = Depends(get_db)):
    key = Key(service_key='testkey1', service_value='testvalue1')
    service = CreateService(
        name="testname1",
        version="testversion1",
        is_used=True,
        keys=[key, ]
    )
    response = client.post("/create_service", params={"service": service.dict()})
    assert response.status_code == 200

I tried to post service as json, as CreateService instance and finally as params dictionary. I have no errors at response line only with the last one . But I got 422 response status code. What is wrong?

If it can help:

schemas.py

class Key(BaseModel):
    service_key: str
    service_value: str


class CreateService(BaseModel):
    name: str
    version: str
    is_used: bool
    keys: list[Key]

    class Config:
        orm_mode = True
  • You're trying to post a pydantic object directly and not a dictionary (which is what the TestClient expects to use as its JSON source). You probably want to use `, json=service.dict()` to convert the pydantic model to a dict and use `json` to make the testclient submit it as json to your backend service. You're probably just submitting data to a URL with `?service=)` at the end. – MatsLindh Nov 30 '22 at 11:26
  • Hello! Thank you for your help again. I edited params dictionary as: {"service": service.dict()}. But result is still the same. – Konstantinos Nov 30 '22 at 11:50
  • Chris, it doesn't. But thank you anyway – Konstantinos Dec 02 '22 at 11:01

2 Answers2

0

Don't use params. Use json:

response = client.post("/create_service", json=service.dict())
Paweł Rubin
  • 2,030
  • 1
  • 14
  • 25
0

It's better to use jsonable_encoder, e.g.

from fastapi.encoders import jsonable_encoder
response = client.post("/create_service", json=jsonable_encoder(service))

Simple .dict() won't work in cases you have rich data types (e.g. UUIDs).

Bojan Bogdanovic
  • 500
  • 1
  • 6
  • 6