Search code examples
pytestfastapi

Pytest assertion problem for HTTPException: 500


I am having problem about testing a very simple FastAPI end-point and not able to assert HTTPException: 500.

This is my endpoint get AuthenticationRequest from client to get a token from an external system. AuthenticationRequest is nothing but a Username and Password combination.

@authentication_router.post("/authenticate", tags=["Authentication"])
async def authenticate(
    authentication_request: AuthenticationRequest,
    authentication_service: AuthenticationService = Depends()
):
    """
    Authenticate user and retrieve access token.

    Args:v
        authentication_request (AuthenticationRequest): User authentication request.

    Returns:
        dict: Access token if authentication is successful.
    """
    try:
        access_token = authentication_service.authenticate(authentication_request)
        if access_token is None:
            raise HTTPException(status_code=401, detail="Invalid credentials")
        logger.info(f"Authentication is successful for user: {authentication_request.username}")
        return {"access_token": access_token}
    except Exception as e:
        logger.exception("An error occurred during authentication")
        raise HTTPException(status_code=500, detail=str(e))

I can successfully test this end-point with valid credentials (test_valid_authentication() works). However, invalid_credentials case does not work for me since Pytest did not assert status_code=500.

Here is my unit tests:

test_data = ApplicationConfiguration()


@pytest.fixture
def client():
    return TestClient(authentication_router)


def test_valid_authentication(client):
    authentication_data = {"username": test_data.TEST_USER, "password": test_data.TEST_PASSWORD}
    response = client.post("/authenticate", json=authentication_data)
    assert response.status_code == 200
    assert "access_token" in response.json()


def test_invalid_authentication(client):
    authentication_data = {"username": "invalid_user", "password": "invalid_password"}
    response = client.post("/authenticate", json=authentication_data)
    assert response.status_code == 500

Since I am using another client at my endpoint, I am wrapping original 401 error with another exception status code which is 500. I was expecting this test to be successful as well since I am asserting response.status_code == 500 in my test.

I want to pass my test_invalid_authentication() according to response status code = 500. Could you please help about the missing point here.

Pytest Results:

    @authentication_router.post("/authenticate", tags=["Authentication"])
    async def authenticate(
        authentication_request: AuthenticationRequest,
        authentication_service: AuthenticationService = Depends()
    ):
        """
        Authenticate user and retrieve access token.

        Args:v
            authentication_request (AuthenticationRequest): User authentication request.

        Returns:
            dict: Access token if authentication is successful.
        """
        try:
            access_token = authentication_service.authenticate(authentication_request)
            if access_token is None:
>               raise HTTPException(status_code=401, detail="Invalid credentials")
E               fastapi.exceptions.HTTPException: 401: Invalid credentials

routers\authentication.py:28: HTTPException

During handling of the above exception, another exception occurred:

   @authentication_router.post("/authenticate", tags=["Authentication"])
    async def authenticate(
        authentication_request: AuthenticationRequest,
        authentication_service: AuthenticationService = Depends()
    ):
        """
        Authenticate user and retrieve access token.

        Args:v
            authentication_request (AuthenticationRequest): User authentication request.

        Returns:
            dict: Access token if authentication is successful.
        """
        try:
            access_token = authentication_service.authenticate(authentication_request)
            if access_token is None:
                raise HTTPException(status_code=401, detail="Invalid credentials")
            logger.info(f"Authentication is successful for user: {authentication_request.username}")
            return {"access_token": access_token}
        except Exception as e:
            logger.exception("An error occurred during authentication")
>           raise HTTPException(status_code=500, detail=str(e))
E           fastapi.exceptions.HTTPException: 500: 401: Invalid credentials


====================================================================== short test summary info ======================================================================= 
FAILED tests\test_authentication.py::test_invalid_authentication - fastapi.exceptions.HTTPException: 500: 401: Invalid credentials
============================================================== 1 failed, 1 passed, 4 warnings in 1.46s =============================================================== 

Solution

  • This simplified code example works fine for me.

    from fastapi import FastAPI, HTTPException
    from fastapi.testclient import TestClient
    
    app = FastAPI()
    
    
    @app.post("/authenticate")
    def authenticate():
        try:
            access_token = None
            if access_token is None:
                raise HTTPException(status_code=401, detail="Invalid credentials")
            return {"access_token": access_token}
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))
    
    
    
    client = TestClient(app)
    
    def test_invalid_authentication():
        authentication_data = {"username": "invalid_user", "password": "invalid_password"}
        response = client.post("/authenticate", json=authentication_data)
        assert response.status_code == 500
    
    

    I think your code also should work. If not, try to create minimal code example that reproduces the problem. So that we can just copy and run it.