Django Testing
**************

.. highlight:: python

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 :doc:`dev-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.