V
V
Vlad2021-07-18 13:23:12
Python
Vlad, 2021-07-18 13:23:12

What is the correct way to apply mock post.request in a FastAPI test?

there is an endpoint, upon request, to which a file is returned in response (conversion from pdf to text):

@router.post('/upload_file/', status_code=status.HTTP_200_OK)
async def upload_file(url: AnyUrl = None, file: UploadFile = File(None)) -> Response:
 ###логика


In the logic of this endpoint, I have another post request for another endpoint. In fact, the details of how the program works are not needed here. I just can’t figure out how, for test purposes, I can do it in such a way that I don’t access this internal endpoint (replace it with pre-prepared data).

Here is the logic of my endpoint:

async def get_response(file: Union[UploadFile, bytes], endpoint=settings.PDF_TO_JPEG_ENDPOINT):
    """Getting response from endpoint and passing it further for converting"""
    async with aiohttp.ClientSession() as session:
        uploaded_file = {'file': file}
        if type(file) != bytes:
            uploaded_file = {'file': await file.read()}  # multipart encoded file
        async with session.post(endpoint, data=uploaded_file) as resp:
            return await main(await resp.content.read())


async def get_file_from_url(url: AnyUrl):
    """Get file from URL"""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.content.read()


def unzip(resp: bytes) -> List[bytes]:
    """Extract pages from archive"""
    pages = []
    with ZipFile(BytesIO(resp)) as unziped_pages:
        for page in unziped_pages.namelist():
            pages.append(unziped_pages.read(page))
        return pages


def ocr_pages(page: bytes):
    """OCR pages extracted from archive"""
    with Image.open(BytesIO(page)) as im:
        with PyTessBaseAPI(lang=settings.TESSEROCR_DEFAULT_LANG, psm=PSM.AUTO_OSD,
                           oem=OEM.TESSERACT_ONLY) as api:
            api.SetImage(im)
            text = api.GetUTF8Text()
            word_conf = api.MapWordConfidences()
    return text, word_conf


def combine_two(resp: bytes):
    start = time.time()
    pages = unzip(resp)
    text_response = ''
    with ProcessPoolExecutor(max_workers=5) as pool:
        result = pool.map(ocr_pages, pages)
    for page_text, _ in result:
        text_response += page_text
    print('FINISHED AT {:.1f} sec'.format(time.time() - start))
    return text_response


async def main(resp: bytes):
    loop = asyncio.get_running_loop()
    with ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, partial(combine_two, resp))
    return result


I'm actually interested in the line at the very top
async with session.post(endpoint, data=uploaded_file) as resp:


I wrote a mock request for it so that a pre-prepared file comes in response.:

with requests_mock.Mocker() as m:
    m.post(settings.PDF_TO_JPEG_ENDPOINT, content=open(PATH, 'rb').read())
    resp = requests.post(settings.PDF_TO_JPEG_ENDPOINT)


But what doesn’t fit in my head is how and where to insert this mock into my test so as not to copy all the above logic into it.

those. What I would like to receive:

client = TestClient(app)

def test_do_something():
    response = client.post('/upload_file/')
    #делаю что-нибудь с response#
    #делаю какой-нибудь assert#

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question