Django Testing

Download

assert HTTPStatus.OK == response.status_code
content = io.BytesIO(b"".join(response.streaming_content))
assert "1-2-3" == content.read().decode("utf-8").strip()
assert (
    'inline; filename="{}-1-2-3.txt"'.format(record.pk)
    == response["Content-Disposition"]
)

CSV

Tip

The view under test is Django View.

import io

@pytest.mark.django_db
def test_report_consent_user():
    with io.StringIO() as response:
        result = _report(response)
        response.seek(0)
        result = response.readlines()
    header = "name,email,consent\r\n"
    assert [
        header,
        "A Kimber,a@test.com,Y\r\n",
        "B Orange,b@b.com,\r\n",
    ] == result

Database

from django.db import IntegrityError

with pytest.raises(IntegrityError):
    # ...

# not sure if the following is sensible (or not)?
assert "duplicate key value violates unique constraint" in str(e.value)
assert "pipeline_pipelinestep_pipeline_id_order" in str(e.value)

Errors

form = response.context["form"]
assert {
    "comments": ["This field is required."],
    "result": ["This field is required."],
} == form.errors

factory

If you have a factory which includes a FileField:

import factory

class DocumentFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Document

    document_file = factory.django.FileField(filename="my_document.doc")

You can supply a different file in the actual test as follows:

from django.core.files.uploadedfile import SimpleUploadedFile

document = DocumentFactory(
    document_file=SimpleUploadedFile("your_document.doc", b"file contents"),
)

Or:

sample_pdf_file = pathlib.Path(
    pathlib.Path.cwd(), "document", "tests", "data", "sample.pdf"
)
with open(sample_pdf_file, "rb") as f:
    document_file = SimpleUploadedFile("my_blank_form.pdf", f.read())
document = DocumentFactory(document_file=document_file)

Tip

Don’t forget rb in the open if this is a binary file.

Initial

Use form.initial:

assert HTTPStatus.OK == response.status_code
assert "form" in response.context
form = response.context["form"]
assert user == form.initial["name"]

If there are no initial values set on a form:

assert {} == form.initial

Messages

assert "messages" in response.context
messages = response.context["messages"]
assert 1 == len(messages)
assert ["Cannot create invoice - no hourly rate"] == [
    str(x) for x in messages
]

Queryset

form = response.context["form"]
name = form.fields["name"]
assert ["a", "c"] == [x.username for x in name.queryset]

RequestFactory

It might be easier to test views using a request factory. pytest-django includes rf, a request factory fixture:

def test_title(rf):
    url = reverse("mailing.list")
    request = rf.post(url, data={"category_id": category_id})
    request.user = UserFactory(is_staff=True)
    response = MailingListReportFormView.as_view()(request)
    assert HTTPStatus.FOUND == response.status_code

Note

If the view needs an authenticated user, we set the user on the request.