django-ninja
django-ninja copied to clipboard
[1061] Add `resolver_match` to the mocked request object in the Ninja's TestClient
The problem
Previously, the Ninja's TestClient did not include the resolver_match in the mocked request object. That's causing issue when having the following setup:
# in schemas.py
class EntityUpdateSchema(Schema):
id: int
class Meta:
exclude: ("id",)
fields_optional = "__all__"
model = Entity
@staticmethod
def resolve_id(obj, context):
return context["request"].resolver_match.kwargs.get("id")
The above schema will infer the id property from the path. So, assuming you have the following path:
@router.patch("/entities/{id}/")
def patch_entity(request: HttpRequest, id: int, partial_entity_data: EntityUpdateSchema):
...
the EntityUpdateSchema will be populated with the id received from the path. I find this useful for when we need to do some validation against the object and we need to query the object that we're currently working with.
And the good news is - this works perfectly! When I call the endpoint, everything is behaving as it should :chef-kiss:
So, what's the problem?
When writing tests, though, and using the TestClient from Ninja, this is not working at all. Doing client.patch("/entities/123") will never populate the schema field, and we will get a validation error back, saying the id field is missing.
The solution
The solution for this is quite simple - when we build the mock request object, we need to set the resolver_match to the ninja resolver that we get back from the URL. By doing that, the schema is again able to infer the id and everything works as it should, even in tests.
While I could just create my own TestClient that would inherit from Ninja's test client, and override the _resolve method, I assume this would be beneficial to others as well. Hence, creating a PR with the fix in hopes that others will find it useful as well.
@vitalik any thoughts re this?:)