0

I'm trying to test my /login API with FastAPI's Testclient.

But when I pass data to the post api. It shows, 422 error with content username and password fields are required.

API:


@router.post('/token', response_model=schemas.Token)
async def login(user_credentials: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
    """
    Login to the system with (Email | Username | Contact)
    """

    user = db.query(models.User).filter(
        (models.User.email == user_credentials.username) |
        (models.User.username == user_credentials.username) |
        (models.User.contact == user_credentials.username)
    ).first()

    if not user:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Invalid Credentials"
        )

    if not utils.verify_pwd(user_credentials.password, user.password):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Invalid Credentials"
        )

    access_token = oauth2.create_access_token(data={'user_id': user.id})

    return {"access_token": access_token, "token_type": "bearer"}

Test Code:

from fastapi.testclient import TestClient

from ..main import app


client = TestClient(app)


def test_auth_token(get_client: TestClient):
    client = get_client.post('/token', json={"username": "admin", "password": "1234567890"})
    assert client.status_code == 200

Error

(venv)  ✘ genex@Genexs-MacBook-Pro: pytest -s
================================================================================== test session starts ===================================================================================
platform darwin -- Python 3.10.8, pytest-7.2.1, pluggy-1.0.0
rootdir: /Users/genex/Desktop/basha-bari
plugins: asyncio-0.20.3, anyio-3.6.2
asyncio: mode=strict
collected 1 item                                                                                                                                                                         

apps/utility/test_utility_routers.py {'detail': [{'loc': ['body', 'username'], 'msg': 'field required', 'type': 'value_error.missing'}, {'loc': ['body', 'password'], 'msg': 'field required', 'type': 'value_error.missing'}]}
F

======================================================================================== FAILURES ========================================================================================
____________________________________________________________________________________ test_auth_token _____________________________________________________________________________________

    def test_auth_token():
        result = client.post('/token', json={"username": "admin", "password": "1234567890"})
        print(result.json())
>       assert result.status_code == 200
E       assert 422 == 200
E        +  where 422 = <Response [422 Unprocessable Entity]>.status_code

apps/utility/test_utility_routers.py:12: AssertionError
================================================================================ short test summary info =================================================================================
FAILED apps/utility/test_utility_routers.py::test_auth_token - assert 422 == 200
=================================================================================== 1 failed in 1.06s ====================================================================================

I'm using httpx and pytest.

How should I pass the payload, so that the API receives it.

Chris
  • 18,724
  • 6
  • 46
  • 80
Fahad Md Kamal
  • 243
  • 6
  • 20
  • in `test_auth_token` you need to post `data` not `json`. `client = get_client.post('/token', data={"username": "admin", "password": "1234567890"})` – Artem Strogin Feb 28 '23 at 20:02
  • 2
    .. and the reason is that they're expected as form values, not as a JSON body. – MatsLindh Feb 28 '23 at 20:07

1 Answers1

0

You are sending JSON with "content-type": "application/x-www-form-urlencoded" that's the problem here, you should send request as form data. Try to change:

response = client.post("/token", data={"username": "admin", "password": "1234567890", "grant_type": "password"},
                           headers={"content-type": "application/x-www-form-urlencoded"})
ozs
  • 3,051
  • 1
  • 10
  • 19