pythondjangodjango-ninja

Django Ninja Testing


I am trying to create a test for an API I wrote using Django-Ninja.

Here is my Model:

class Country(models.Model):
    created_at = models.DateTimeField(auto_created=True, auto_now_add=True)
    name = models.CharField(max_length=128, null=False, blank=False)
    code = models.CharField(max_length=128, null=False, blank=False, unique=True)
    timezone = models.CharField(max_length=128, null=False, blank=False)

Here is my schema:

class CountryAddSchema(Schema):
    name: str
    code: str
    timezone: str

Here is the post endpoint:

router.post("/add",
             description="Add a Country",
             summary="Add a Country", tags=["Address"],
             response={201: DefaultSchema, 401: DefaultSchema, 422: DefaultSchema, 500: DefaultSchema},
            url_name="address_country_add")
def country_add(request, country: CountryAddSchema):
    try:
        if not request.auth.belongs_to.is_staff:
            return 401, {"detail": "None Staff cannot add Country"}

        the_country = Country.objects.create(**country.dict())
        the_country.save()
        return 201, {"detail": "New Country created"}
    except Exception as e:
        return 500, {"detail": str(e)}

Finally, here the test function:

def test_add_correct(self):
    """
    Add a country

    """
    data = {
        "name": "".join(choices(ascii_letters, k=32)),
        "code": "".join(choices(ascii_letters, k=32)),
        "timezone": "".join(choices(ascii_letters, k=32))
    }

    respond = self.client.post(reverse("api-1.0.0:address_country_add"), data, **self.AUTHORIZED_HEADER)
    self.assertEquals(respond.status_code, 201)
    self.assertDictEqual(json.loads(respond.content), {"detail": "New Country created"})

    the_country = Country.objects.last()
    self.assertDictEqual(
        data,
        {
            "name": the_country.name,
            "code": the_country.code,
            "timezone": the_country.timezone
        }
    )

Please notice I have self.AUTHORIZED_HEADER set in setUp.

And here the error:

FAIL: test_add_correct (address.tests_country.CountryTest)
Add a country
----------------------------------------------------------------------
Traceback (most recent call last):
  File "SOME_PATH/tests_country.py", line 80, in test_add_correct
    self.assertEquals(respond.status_code, 201)
AssertionError: 400 != 201

I can add a country using swagger provided with django-ninja. I mean the endpoint works. But I can not test it using djano.test.Client.

Any Idea?

Update:

Here the curl code generated by swagger:

curl -X 'POST' \
  'http://127.0.0.1:8000/api/address/country/add' \
  -H 'accept: application/json' \
  -H 'X-API-Key: API-KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "string",
  "code": "string",
  "timezone": "string"
}'

Solution

  • I had {"detail": "Cannot parse request body"} as an error.

    Turns out, Django-ninja expects your data to be passed as a json, but by default, the content_type is set to multipart/form-data; boundary=BoUnDaRyStRiNg for the test client. When you explicitely mention the content type should be json, it will work.

    Client().post(url, {"your": "dict"}, content_type="application/json")
    

    Note: Setting the content-type in the headers will not work as it will get overwritten.