Learn from Source: Master Testing in Django
Tags: django, unittest, python
Published: 2023-12-26 14:06:43

Testing is a fundamental part of the development. We test to find bugs, and one of the places we often need testing is database queries. While working and learning from the Django core repository, I encountered different unit test cases. They test raw queries. In this blog post, we will delve into two specific Django test methods that highlight some interesting unit tests: passing optional query parameters and understanding the lazy nature of raw queries.

## Optional Query Parameters Test:

**Understanding the Test:**

Let's first revisit the test_params Django test method, which is designed to evaluate the handling of optional query parameters. The test focuses on passing parameters to a raw SQL query and performing assertions to validate the correctness of the results.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uewzi3mdzo63buwgs30e.jpeg)



Let's break down the assertions to understand them better:

`self.assertProcessed(Author, results, [author]):
`
This assertion ensures that the raw SQL query results (results) have been processed correctly for the Author model.
The Author model and the expected list of authors ([author]) are passed as arguments.

`self.assertNoAnnotations(results):
`
This assertion verifies that there are no annotations present in the raw SQL query results. Annotations in Django are additional metadata associated with query results. For example number of entries.

`self.assertEqual(len(results), 1):
`
This assertion checks that the length of the results list is equal to 1. It ensures that the raw SQL query returns exactly one result, as expected.

`self.assertIsInstance(repr(qset), str):
`
This assertion confirms that the representation of the query set (qset) is an instance of a string (str). This is a useful check to ensure that the query set can be represented as a string.

Attention to use of repr built-in function.

> repr(object)
> Return a string containing a printable representation of an object.

## Lazy Raw Queries Test:

**Introducing the Test:**

In addition to testing optional query parameters, Django developers must be aware of the lazy nature of raw queries. The test_raw_query_lazy method explores this characteristic, emphasizing that raw queries are not executed until they are iterated over. the last line is the key to understanding this code. Take a look at the code below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbjb7v7pzw77cv0wcss7.jpeg)



Breaking Down the Test Steps and Assertions:

`q = Author.objects.raw("SELECT * FROM raw_query_author"):`

This line defines a raw SQL query using Author.objects.raw(). Importantly, the query is not executed at this stage.

`self.assertIsNone(q.query.cursor):`

This assertion checks that the raw SQL query has not been executed initially. It does so by verifying that the cursor attribute of the query is None.

`list(q):
`

This line triggers the execution of the raw SQL query by iterating over it using the list() function. This is the point at which the lazy execution occurs.

`self.assertIsNotNone(q.query.cursor):
`
After iterating over the query, this assertion confirms that the raw SQL query has been executed. It does so by checking that the cursor attribute of the query is now not None.

Very interesting setup here. We see how we create a raw query execute it and check it with the last assertion. Look at the `list()` function.

The main goal of this post was to make you familiar with testing and how the Django test can be written.

Comment your thoughts below. Until next time.

To read more about the list: check out this part of the [documentation](https://docs.djangoproject.com/en/5.0/ref/models/querysets/#when-querysets-are-evaluated).