0

This is the first time I'm trying to write test cases.

I've got a simple FastAPI application and I'm trying to create tests with unittest module.

My goal is to test how app behaves for success case

I've got a simple route in my app:

from fastapi import APIRouter,Request  
import requests 

router = APIRouter()


@router.post("/demo_router")
async def demo_api(request: Request):
   # now calling some private APi's
   
  
   resp = requests.post("https://example.com", json=data)

   

   return {"resp_data": resp.json()}

Now in my unittest module I'm trying to patch above api. I'm using unittest.mock but I'm getting very strange behavior.

  import unittest
  from fastapi.testclient import TestClient
  from unittest.mock import patch
  from main import app
  
   class DemoViewTestCase(unittest.TestCase):

       def test_demo_api(self):
           with patch('src.endpoints.demo_module.demo_api') as mocked_post:
               mocked_post.return_value.status_code = 200
               mocked_post.return_value.json = {
                   "message": "request accepted",
                   "success": True
                   }
                url = router.url_path_for('demo_api')   #fetch the api router
                client = TestClient(app)
                response = client.post(url, json={"id": "BXBksk8920", "name": "Pjp"})

My problem is TestClient is calling the api and executing it. So it is triggering the internal call "https://example.com" which is causing some execution in the pipelines. So how can I overcome this?

Internal Api shouldn't trigger, I should even mock that? Any solution for that?

praveen jp
  • 65
  • 10
  • Mocking the _endpoint_ that you're testing seems like a bad idea - the only thing you're testing in that case is that a function is returning what you said it should return - i.e. you're not testing your code at all (if you're testing _something_, it would be the mock library or FastAPI - let FastAPI test FastAPI). Instead, you should mock `requests.post` and make sure that the request is made with the expected URL and return the content that a successful POST would return - so that you test that _your_ code does what it's supposed to and you have the expected behavior. – MatsLindh Jun 17 '22 at 07:32

1 Answers1

0

When testing all the code will be executed. Thus also the calls to the APIs. If you don't want this, you have to provide mock APIs (postman, mockon and many others provide this). Because you don't want to be bothered to change the URL's etc when you are testing etc, you could look at automating this.

One way of doing this is to provide all URLs for external APIs using pedantic BaseSettings

config.py:

from pydantic import BaseSettings

class Settings(BaseSettings):
    external_api_url: str = "https://api.example.com"

And use this in your code:

settings = Settings() # scans environment for any matching env settings!
...
resp = requests.post(setting.external_api_url, json=data)

In your tests you can override these settings:

settings = Settings(external_api_url="https://mockservice")

This is documented further in Pydantic BaseSettings

There are more way do enhance testing and this is found at the FastAPI documentation: Dependency Override: https://fastapi.tiangolo.com/advanced/testing-dependencies/

Use different databases for testing: https://fastapi.tiangolo.com/advanced/testing-database/

Charlie V
  • 980
  • 1
  • 6
  • 12