patch()
是 Django 测试框架中的一个重要函数,用于在测试环境中模拟和修改外部依赖项(如数据库,API请求等)。它的主要作用是将一个对象替换为另一个对象,以便在单元测试中更好地控制测试环境。以下是 patch()
函数的详细说明:
patch()
函数的使用方法
patch()
函数可以通过以下方法进行调用:
from unittest.mock import patch
@patch('package.module.Class.method')
def test_method(mocked_method):
# code
在上述代码块中,patch()
函数将 package.module.Class.method
这个方法用一个 Mock()
对象(或其他指定的对象)代替。我们可以在测试期间使用 mocked_method
变量,以控制代替该方法所采取的行动。
另外,patch()
还可以用作装饰器,通过更改预先定义的对象,以保证测试正常运作。
import pytest
from django.urls import reverse
from unittest.mock import patch
@pytest.mark.django_db
@patch('project.apps.common.views.Function.class_module')
def test_function(mock_class_module):
# code
在上述代码块中,patch()
作为装饰器使用,将 project.apps.common.views.Function.class_module
类用 Mock 对象代替。我们现在可以在我们的测试中使用 mock_class_module
进行控制了。
patch()
函数的开发实例
下面是两个实例,在实例中,我们将介绍如何使用 patch()
函数来控制大多数基于 Django 的代码库的测试环境。
实例1:测试 Django 视图函数
考虑以下 Django 视图,其中我们将从数据库中检索一些数据,并将其漂亮地呈现给用户:
from django.shortcuts import render
from .models import Picture
def gallery(request):
pictures = Picture.objects.all()
context = {'pictures': pictures}
return render(request, 'gallery.html', context)
现在我们想测试该视图函数,并在测试期间不连接到实际数据库。为了实现这个目标,我们将使用 patch()
来模拟 Picture.objects.all()
方法,以便在测试期间向我们提供伪造的数据。
from django.urls import reverse
from unittest.mock import patch
from django.test import TestCase
class GalleryViewTest(TestCase):
def setUp(self):
self.url = reverse('gallery')
@patch('gallery.models.Picture.objects.all')
def test_gallery_view(self, mock_picture_list):
# create database objects with factory-boy
# save objects to database
mock_picture_list.return_value = objects
response = self.client.get(self.url)
self.assertContains(response, 'Some picture title')
在上述测试用例中,我们使用 patch()
来模拟 Picture.objects.all()
方法,将它代替为一个 Mock 对象,并指定 return_value
为 objects
。这将确保在 response
被获取时,它将包含 Djangot 内置的测试客户端响应,而检索到的数据是伪造的模拟数据。
实例2:测试 REST API 端点
假设我们有一个通过 Django REST Framework 进行构建的 REST API 端点。现在我们想通过单元测试来确保该端点在代码库更改时运作正常。
from rest_framework import generics
from .models import Person
from .serializer import PersonSerializer
class PersonListAPIView(generics.ListAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer
在这个示例中,我们使用 generics.ListAPIView
类提供了一个简单的站点来列出所有的 Person
对象。
现在,我们要测试这个 API 并确保返回所有存在的人员数量。
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from unittest.mock import patch
class PersonListAPIViewTest(APITestCase):
def setUp(self):
self.url = reverse('people-list')
@patch('people.api.views.PersonListAPIView.queryset')
def test_person_list_api_view(self, mock_person_list):
# create database objects with factory-boy
# save objects to database
mock_person_list.return_value.count.return_value = 3
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 3)
在上述代码块中,我们使用 patch()
函数来模拟查询 Person
对象的方法,将其替换为一个 Mock 对象。我们返回的计数值是 3,这将确保我们仅在测试期间返回 3 个对象,测试仅仅返回 3 个人员。