23
loading...
This website collects cookies to deliver better user experience
I do not make a distinction between unit tests and integration tests. I generally refer to these types of tests as unit tests. I do not go out of my way to isolate a single unit of code and test it without consideration of the rest of the project. I do try to isolate a single unit of behaviour.
Article
model in app articles
at articles/models.py
:class Article(models.Model):
...
articles/tests/test_models.py
:class ArticleTest(TestCase):
...
articles/utils.py
:def do_something():
...
articles/tests/test_utils.py
:class DoSomethingTest(TestCase):
def test_do_something(self):
...
DoSomethingTest
extending a TestCase
? Rather than a standalone test function?django.test.TestCase
is in fact a subclass of unittest.TestCase
that runs each test inside a transaction to provide database-oriented goodies. Such as transaction isolation. Django's writing and running tests docs provide more details on this.TestCase
's name should be indicative of the class (or standalone function) being tested. So for classes:class Article(model.model)
...
class ArticleTest(TestCase)
...
def do_something():
...
class DoSomethingTest(TestCase):
def test_do_something(self):
...
class Article(models.Model):
title = models.CharField(max_length=32)
slug = models.CharField(max_length=32, unique=True)
content = models.TextField()
def __str__(self):
return self.title
def get_short_title(self):
if len(self.title) > 15:
return self.title[: (15 - 3)] + "..."
return self.title
get_short_title
based on the title
's length. The more "explicit" the name the better. Have test function names that reflect the state relevant for the expected result:class ArticleTest(TestCase):
def test_get_short_title_title_is_longer_than_15_characters_yes(self):
...
def test_get_short_title_title_is_longer_than_15_characters_no(self):
...
Article
get_short_title
article
to test __str__
:article = baker.make("articles.Article", title="Test Title")
slug
or description
. These would be noise for our test's purpose.11.1
in Speed up your Django Tests delves into more detail why fixture files should just be avoided.RequestFactory
, or APIRequestFactory
in DRF, directly to the view functions. Same approach applies for serializer (or form) functions.get_queryset
.Article
model. This is what we'd find in articles/serializers.py
:class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
articles/views.py
class ArticleListCreateAPIView(generics.ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
class ArticleDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
title
. The easiest option would be to extend ArticleListCreateAPIViewTest.test_list
to:title
s to be able to assert results orderordering
parameterclass ArticleListCreateAPIView(generics.ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = ["title"]
class ArticleListCreateAPIViewTest(APITestCase):
def test_list(self):
article1 = baker.make("articles.Article", title="Title A")
article2 = baker.make("articles.Article", title="Title C")
article3 = baker.make("articles.Article", title="Title B")
# default ordering by id:
response = self.client.get("/api/articles/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
[article["id"] for article in response.data],
[article1.id, article2.id, article3.id]
)
# ordering by title:
response = self.client.get("/api/articles/?ordering=title")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
[article["id"] for article in response.data],
[article1.id, article3.id, article2.id]
)
TestCase
extends unittest
's TestCase
. And DRF's APITestCase
extends Django's TestCase
. This guide does not go into other test runners like pytest
. Which take a more functional approach.coverage
is a "dumb" measure of how many lines in your codebase are "covered by" tests. Why dumb? You can write a bunch HTTP GET requests in your tests, write zero assertions, and increase coverage a lot. That, of course, doesn't add any value.Diff coverage is the percentage of new or modified lines that are covered by tests. This provides a clear and achievable standard for code review: If you touch a line of code, that line should be covered. Code coverage is every developer’s responsibility!