Wrong response code - pytest unit tests for FastAPI app

Hi all, I’m trying to write pytest unit tests for FastAPI app and having issue with wrong response code when not authorized. More details will follow.

FastAPI login functionality:

@app.post("/login")
async def login(request: Request, token: str = Form(...), db: Session = Depends(get_db)):
    
    logging.basicConfig(level = logging.INFO)
    logging.info("post /login")

    users = get_users(db)

    if users:
        logging.debug(f"debug /login - users count: {len(users)}")
    else:
        logging.debug(f"debug /login - Error! users is null")

    authenticated_user = None
    for user in users:
        if pbkdf2_sha256.verify(token, user.token):
            authenticated_user = user
            break

    if authenticated_user:
        user_description = authenticated_user.description
        logging.info('debug 1111')
        #data = {"logout_url": app.url_path_for('logout'),}
        data = {
                "checkmark_url": app.url_path_for('checkmark'),
                "checkmark_negative_url": app.url_path_for('checkmark_negative'),
                "api_requests_url": app.url_path_for('api_requests'),
                "mapping_url": app.url_path_for('mapping'),
                "schedule_list_url": app.url_path_for('schedule_list'),
                "fetch_data_to_csv_route_url": app.url_path_for('fetch_data_to_csv_route'),
                "datasource_url": app.url_path_for('datasource'),
                "secret_tokens_url": app.url_path_for('secret_tokens'),
                "home_url": app.url_path_for('home'),
                "logout_url": app.url_path_for('logout'),
        }
        response = templates.TemplateResponse('dashboard.html', {
            "request": request, 
            "description": user_description, 
            "current_user_id": authenticated_user.id, 
            "current_user_isadmin": authenticated_user.isadmin, 
            "current_user": authenticated_user, 
            "data": data
        }), 200
        #return response
        logging.info('debug 1114')
        user_data = {"sub": "token", "id": authenticated_user.id, "description": user_description, "isadmin": authenticated_user.isadmin, "scopes": ["read", "write"]}
        token_jwt = create_jwt_token(user_data)
        response.set_cookie("token", token_jwt)
        logging.info('debug 1115')

        return response
    else:
        response = templates.TemplateResponse('login.html', {
            "request": request, 
            "messages": messages
        }), 401
        return response

@app.get("/login", name="login", response_class=HTMLResponse)
def login_form(request: Request, next: str = "", current_user: SecretToken = Depends(get_current_user)):
    if current_user is not None:
        logging.info('debug login get - current_user is not None')
        if next:
            response = RedirectResponse(url=next)
        else:
            data = {"logout_url": app.url_path_for('logout'),}
            response = templates.TemplateResponse('dashboard.html', {"request": request, "current_user": current_user, "data": data})
        return response
    else:
        messages = ['please authenticate']
        logging.basicConfig(level = logging.INFO)
        logging.info("get /login")
        logging.info('debug login get - current_user is None')
        logging.info(f'debug login get - request: {str(request)}')
        now = datetime.now()
        logging.info(f'debug login get - now: {now}')
        return templates.TemplateResponse('login.html', {"request": request, "messages": messages}), 401

unit test function:

@pytest.mark.asyncio
async def test_login_wrong_token(client):
    """
    Test if the login view returns the correct response (401 Unauthorized)
    when an incorrect token is provided.
    """
    rv = client.post('/login', data={'token': 'wrong_token'})
    assert rv.status_code == 401, f"Expected status code 401, but got {rv.status_code}"
    print("Test passed: The login view returned the correct response (401 Unauthorized) when an incorrect token was provided.")

pytest output:

mycode1   | ============================= test session starts ==============================
mycode1   | platform linux -- Python 3.10.11, pytest-8.0.0, pluggy-1.4.0
mycode1   | rootdir: /var/www/app
mycode1   | plugins: anyio-4.2.0, asyncio-0.23.5
mycode1   | asyncio: mode=strict
mycode1   | collected 5 items
mycode1   | 
mycode1   | test_app.py FF.FF                                                        [100%]
mycode1   | 
mycode1   | =================================== FAILURES ===================================
mycode1   | ____________________________ test_login_wrong_token ____________________________
mycode1   | 
mycode1   | client = <starlette.testclient.TestClient object at 0x7fcedb6abc70>
mycode1   | 
mycode1   |     @pytest.mark.asyncio
mycode1   |     async def test_login_wrong_token(client):
mycode1   |         """
mycode1   |         Test if the login view returns the correct response (401 Unauthorized)
mycode1   |         when an incorrect token is provided.
mycode1   |         """
mycode1   |         rv = client.post('/login', data={'token': 'wrong_token'})
mycode1   | >       assert rv.status_code == 401, f"Expected status code 401, but got {rv.status_code}"
mycode1   | E       AssertionError: Expected status code 401, but got 200
mycode1   | E       assert 200 == 401
mycode1   | E        +  where 200 = <Response [200 OK]>.status_code
mycode1   | 
mycode1   | test_app.py:61: AssertionError

As I can see, the FastAPI login functionality is set to return 401 error if token is wrong, but the unit test gets 200 anyway.
Please advise.

You’re writing 'debug 1111' or 'debug 1114' to the log. Which is one is there?

If 'debug 1111' is there, does it think the token is valid? Write to the log the token that was provided and, for each user, their token and whether it was passed.