FastAPI unit test returns 422

I am new to python and FastAPI and writing some test code for FastAPI endpoints. I have the following function for unit testing, but when I run it I get back status code 422. Not sure what I am doing wrong:

def test_create_event(self):
        my_date = datetime.date(2023, 6, 15)
        data = {'id': '1', 'title': 'Winter Cooking', 'host': 'Steven',
                'ingredients': ['Apples','Pumpkin','Pecans','Oats'], 
                'date': my_date.strftime('%m-%d-%Y'), 'participants': ['Steven','Kyle']}
        response = requests.post(self.url + '/events/', json=data)
        print("response=" + str(response.status_code))
        self.assertEqual(response.status_code, 201)

The Event class is defined the following way:

class Event(BaseModel):
    id: int
    title: str
    host: str
    ingredients: List[str] = []
    date: datetime
    participants: List[str] = []

My POST method that works is defined here:

# For event creation via POST
@events_router.post("/events/", status_code=201, response_model=Event)
def create_event(*, event_in: EventCreate) -> Event:
    """
    Create a new event (in memory only)
    """
    #change below to be based on global variable counter
    global counter
    new_entry_id = counter
    # TODO: change date to server-side data value
    event_entry = Event(
        id=new_entry_id,
        title=event_in.title,
        host=event_in.host,
        ingredients=event_in.ingredients,
        date=event_in.date,
        participants=event_in.participants
    )
    EVENTS.append(event_entry.dict())
    counter += 1

    return event_entry

Thanks for any advice.

What was the content of the 422 response? The response will say which input failed the validation done by pydantic.

I haven’t run your code, but my first guess is that it fails to convert the str value associated to the key date of the input, into a datetime value for the attribute date of Event. Probably pydantic just tries to give the string to the constructor of datetime.

You can provide a custom validation in which you handle how to turn the string into a datetime value.

Hi Franklin,

I am using PyCharm and the Run screen shows only the error failure when assert does not match:

Traceback (most recent call last):
  File "/Users/steve/PycharmProjects/ChefServices/tests/event_tests_old.py", line 36, in test_create_event
    self.assertEqual(response.status_code, 201)
AssertionError: 422 != 201

I don’t see which field is the issue within PyCharm, something I was hoping to see.
I will try out using custom validation and see how that goes. I’ll update my results here.

Thanks!

You can print the entire response, instead of only the response.status_code.

I ran the debugger and found that it’s the date time format:
b’{“detail”:[{“loc”:[“body”,“date”],“msg”:“invalid datetime format”,“type”:“value_error.datetime”}]}’

Looks like you were right about it being datetime related.
I changed the values to ISO8601 format and viola it works.
Here is my new code:

def test_create_event(self):
        my_date = my_date = datetime.now(timezone.utc).replace(microsecond=0).astimezone().isoformat()
        print("my_date="+my_date)
        data = {'id': '1', 'title': 'Winter Cooking', 'host': 'Steven',
                'ingredients': ['Apples','Pumpkin','Pecans','Oats'], 
                'date': my_date, 'participants': ['Steven','Kyle']}
        response = requests.post(self.url + '/events/', json=data)
        print("response=" + str(response.status_code))
        self.assertEqual(response.status_code, 201)

Thanks for getting me on the right path!

1 Like