Question: Consider this mcve: requirements.txt: fastapi httpx motor pydantic[email] python-bsonjs uvicorn==0.24.0  main.py: import asyncio import unittest from typing import Optional import motor.motor_asyncio from bson import ObjectId from fastapi import APIRouter, Body, FastAPI, HTTPException, Request, status from fastapi.testclient import TestClient from pydantic import BaseModel, ConfigDict, EmailStr, Field from pydantic.functional_validators import BeforeValidator from typing_extensions import Annotated # -------- Model -------- PyObjectId = Annotated[str, BeforeValidator(str)] class ItemModel(BaseModel): id: Optional[PyObjectId] = Field(alias="_id", default=None) name: str = Field(...) email: EmailStr = Field(...) model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_schema_extra={ "example": {"name": "Jane Doe", "email": "jdoe@example.com"} }, ) # -------- Router -------- mcve_router = APIRouter() @mcve_router.post( "", response_description="Add new item", response_model=ItemModel, status_code=status.HTTP_201_CREATED, response_model_by_alias=False, ) async def create_item(request: Request, item: ItemModel = Body(...)): db_collection = request.app.db_collection new_bar = await db_collection.insert_one( item.model_dump(by_alias=True, exclude=["id"]) ) created_bar = await db_collection.find_one({"_id": new_bar.inserted_id}) return created_bar @mcve_router.get( "/{id}", response_description="Get a single item", response_model=ItemModel, response_model_by_alias=False, ) async def show_item(request: Request, id: str): db_collection = request.app.db_collection if (item := await db_collection.find_one({"_id": ObjectId(id)})) is not None: return item raise HTTPException(status_code=404, detail=f"item {id} not found") if __name__ == "__main__": app = FastAPI() app.include_router(mcve_router, tags=["item"], prefix="/item") app.db_client = motor.motor_asyncio.AsyncIOMotorClient( "mongodb://127.0.0.1:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false" ) app.db = app.db_client.mcve_db app.db_collection = app.db.get_collection("bars") class TestAsync(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.client = TestClient(app) async def asyncTearDown(self): self.client.app.db_client.close() def run_async_test(self, coro): loop = asyncio.get_event_loop() return loop.run_until_complete(coro) def test_show_item(self): bar_data = {"name": "John Doe", "email": "johndoe@example.com"} create_response = self.client.post("/item", json=bar_data) self.assertEqual(create_response.status_code, 201) created_item_id = create_response.json().get("id") self.assertIsNotNone(created_item_id) response = self.client.get(f"/item/{created_item_id}") self.assertEqual(response.status_code, 200) unittest.main()  When I try to run it I'll get this crash: (venv) d:\mcve>python mcve.py E ====================================================================== ERROR: test_show_item (__main__.TestBarRoutesAsync.test_show_item) ---------------------------------------------------------------------- Traceback (most recent call last): File "D:\software\python\3.11.3-amd64\Lib\unittest\async_case.py", line 90, in _callTestMethod if self._callMaybeAsync(method) is not None: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\unittest\async_case.py", line 112, in _callMaybeAsync return self._asyncioRunner.run( ^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\asyncio\runners.py", line 118, in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\asyncio\base_events.py", line 653, in run_until_complete return future.result() ^^^^^^^^^^^^^^^ File "d:\mcve\mcve.py", line 87, in test_show_item response = self.client.get(f"/item/{created_item_id}") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\starlette\testclient.py", line 502, in get return super().get( ^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 1055, in get return self.request( ^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\starlette\testclient.py", line 468, in request return super().request( ^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 828, in request return self.send(request, auth=auth, follow_redirects=follow_redirects) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 915, in send response = self._send_handling_auth( ^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 943, in _send_handling_auth response = self._send_handling_redirects( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 980, in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\httpx\_client.py", line 1016, in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\starlette\testclient.py", line 344, in handle_request raise exc File "D:\mcve\venv\Lib\site-packages\starlette\testclient.py", line 341, in handle_request portal.call(self.app, scope, receive, send) File "D:\mcve\venv\Lib\site-packages\anyio\from_thread.py", line 288, in call return cast(T_Retval, self.start_task_soon(func, *args).result()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\concurrent\futures\_base.py", line 456, in result return self.__get_result() ^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\concurrent\futures\_base.py", line 401, in __get_result raise self._exception File "D:\mcve\venv\Lib\site-packages\anyio\from_thread.py", line 217, in _call_func retval = await retval_or_awaitable ^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\fastapi\applications.py", line 1054, in __call__ await super().__call__(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\applications.py", line 116, in __call__ await self.middleware_stack(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\middleware\errors.py", line 186, in __call__ raise exc File "D:\mcve\venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__ await self.app(scope, receive, _send) File "D:\mcve\venv\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in __call__ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\_exception_handler.py", line 55, in wrapped_app raise exc File "D:\mcve\venv\Lib\site-packages\starlette\_exception_handler.py", line 44, in wrapped_app await app(scope, receive, sender) File "D:\mcve\venv\Lib\site-packages\starlette\routing.py", line 746, in __call__ await route.handle(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\routing.py", line 288, in handle await self.app(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\routing.py", line 75, in app await wrap_app_handling_exceptions(app, request)(scope, receive, send) File "D:\mcve\venv\Lib\site-packages\starlette\_exception_handler.py", line 55, in wrapped_app raise exc File "D:\mcve\venv\Lib\site-packages\starlette\_exception_handler.py", line 44, in wrapped_app await app(scope, receive, sender) File "D:\mcve\venv\Lib\site-packages\starlette\routing.py", line 70, in app response = await func(request) ^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\fastapi\routing.py", line 299, in app raise e File "D:\mcve\venv\Lib\site-packages\fastapi\routing.py", line 294, in app raw_response = await run_endpoint_function( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\fastapi\routing.py", line 191, in run_endpoint_function return await dependant.call(**values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "d:\mcve\mcve.py", line 57, in show_item if (item := await db_collection.find_one({"_id": ObjectId(id)})) is not None: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\motor\metaprogramming.py", line 75, in method return framework.run_on_executor( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\mcve\venv\Lib\site-packages\motor\frameworks\asyncio\__init__.py", line 85, in run_on_executor return loop.run_in_executor(_EXECUTOR, functools.partial(fn, *args, **kwargs)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\software\python\3.11.3-amd64\Lib\asyncio\base_events.py", line 816, in run_in_executor self._check_closed() File "D:\software\python\3.11.3-amd64\Lib\asyncio\base_events.py", line 519, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed ---------------------------------------------------------------------- Ran 1 test in 0.074s FAILED (errors=1)  The line that's producing that crash is response = self.client.get(f"/item/{created_item_id}") but I don't understand what's the issue. Btw, not interested on using pytest at all, the main purpose of this question is to figure what's wrong and how to fix the current mcve Thanks in advance!

Answer: From what I understand from your question, you are also facing issues while running FastAPI. To solve the unit test issue, try creating a test_app.py file in your directory and paste the following code: import asyncio import unittest from fastapi.testclient import TestClient from abhyas import app class TestAsync(unittest.IsolatedAsyncioTestCase): async def asyncSetUp(self): self.client = TestClient(app) async def asyncTearDown(self): self.client.app.db_client.close() async def run_async_test(self, coro): return asyncio.run(coro) async def test_show_item(self): async def test_logic(): bar_data = {"name": "John Doe", "email": "johndoe@example.com"} create_response = await self.client.post("/item", json=bar_data) self.assertEqual(create_response.status_code, 201) created_item_id = create_response.json().get("id") self.assertIsNotNone(created_item_id) response = await self.client.get(f"/item/{created_item_id}") self.assertEqual(response.status_code, 200) self.run_async_test(test_logic) if __name__ == "__main__": unittest.main()  It directly utilizes asyncio.run for running asynchronous coroutines, and the test methods themselves are marked as asynchronous. After separating the unit test code from the FastAPI application. The mcve.py will look like this: from typing import Optional import motor.motor_asyncio import uvicorn from bson import ObjectId from fastapi import APIRouter, Body, FastAPI, HTTPException, Request, status from pydantic import BaseModel, ConfigDict, EmailStr, Field from pydantic.functional_validators import BeforeValidator from typing_extensions import Annotated # -------- Model -------- PyObjectId = Annotated[str, BeforeValidator(str)] class ItemModel(BaseModel): id: Optional[PyObjectId] = Field(alias="_id", default=None) name: str = Field(...) email: EmailStr = Field(...) model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_schema_extra={ "example": {"name": "Jane Doe", "email": "jdoe@example.com"} }, ) # -------- Router -------- mcve_router = APIRouter() @mcve_router.post( "", response_description="Add new item", response_model=ItemModel, status_code=status.HTTP_201_CREATED, response_model_by_alias=False, ) async def create_item(request: Request, item: ItemModel = Body(...)): db_collection = request.app.db_collection new_bar = await db_collection.insert_one( item.model_dump(by_alias=True, exclude=["id"]) ) created_bar = await db_collection.find_one({"_id": new_bar.inserted_id}) return created_bar @mcve_router.get( "/{id}", response_description="Get a single item", response_model=ItemModel, response_model_by_alias=False, ) async def show_item(request: Request, id: str): db_collection = request.app.db_collection if (item := await db_collection.find_one({"_id": ObjectId(id)})) is not None: return item raise HTTPException(status_code=404, detail=f"item {id} not found") app = FastAPI() app.include_router(mcve_router, tags=["item"], prefix="/item") app.db_client = motor.motor_asyncio.AsyncIOMotorClient( "mongodb://127.0.0.1:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false" ) app.db = app.db_client.mcve_db app.db_collection = app.db.get_collection("bars") if __name__ == '__main__': uvicorn.run("mcve:app", host="0.0.0.0", port=8000, reload=True)  If you need help setting up MongoDB locally, you can refer to this page.