发布于 2026-01-06 0 阅读
0

在 Django 中进行测试

在 Django 中进行测试

测试在软件开发生命周期中至关重要,它确保应用程序符合所需的质量标准并按预期运行。测试系统地评估软件组件、模块或系统,以识别错误、缺陷或与预期行为的偏差。

测试有助于降低风险、提高可靠性并改善整体用户体验。

测试的主要目标是发现软件系统的缺陷或预期结果与实际结果之间的差异。

通过执行一系列预定义的测试用例,开发人员和质量保证专业人员可以验证软件的正确性、完整性和健壮性。测试还有助于识别性能瓶颈、安全漏洞和兼容性问题。

测试类型

软件开发过程中通常会执行多种类型的测试,包括:

  • 单元测试:这类测试侧重于单独测试单个单元或组件。
  • 集成测试:这些测试验证多个单元之间的交互和集成。
  • 系统测试:这些测试验证软件系统的整体功能。
  • 验收测试:这些测试由用户或客户执行,以验证软件是否满足其要求。

测试可以手动执行,也可以使用自动化测试框架和工具执行。由于自动化测试具有高效、可重复和可扩展等优点,因此在现代软件开发中更受欢迎。

它允许创建可自动执行的测试套件,使开发人员能够及早发现问题并简化开发过程。

测试并非软件开发中的独立环节,而是开发工作流程中不可或缺的一部分。它应该贯穿整个开发周期,从需求收集和设计的早期阶段,到实现阶段,直至部署和维护阶段。

这种迭代测试方法可确保及时发现和修复缺陷,从而降低返工和修复错误相关的成本和工作量。

本文将探讨如何使用 Django 进行测试。让我们先来了解一下 Django 是什么。

Django是什么?

Django是一个用 Python 编写的开源 Web 框架,它遵循模型-视图-模板 (MVT) 架构模式。Django 提供了一套全面的工具、库和功能,使开发人员能够创建可扩展、安全且易于维护的 Web 应用程序。

它由Django 软件基金会维护。Django 的一些主要功能包括:即用型管理界面/面板、国际化和本地化支持、模板引擎、对象关系映射 (ORM) 和测试框架等。

Django 因其多功能性、可扩展性和强大的社区支持而被开发者广泛使用。它是 Python Web 开发的热门选择。

先决条件

要继续阅读本文,需要以下内容。

  • 熟悉Python和Django语法。
  • 具备一些测试方面的知识。

使用 Django 进行测试

要在 Django 中进行测试,首先需要下载库。下载 Django 可以使用pip pip。本文中,我们将使用pip来管理本地计算机上的下载。为此,我们需要在终端中运行以下命令:

pip install django
Enter fullscreen mode Exit fullscreen mode

django-admin安装 Django 后,我们使用关键字创建一个项目。

django-admin startproject progy .
Enter fullscreen mode Exit fullscreen mode

这将为我们的项目创建基础模板。接下来,我们将创建一个应用程序。应用程序是一个独立的模块或组件,它封装了 Web 应用程序的特定功能或特性。我们将把我们的应用程序命名为account

django-admin startapp account
Enter fullscreen mode Exit fullscreen mode

制作完成后,它的样子会和这个类似。

VScode 中 Django 应用的屏幕截图

接下来,我们将我们的应用程序集成到INSTALLED APPS系统中。[settings.py]

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',

        "account", # our app
    ]
Enter fullscreen mode Exit fullscreen mode

在我们的基础目录中urls.py,我们包含了应用程序的 URL 文件。
注意:创建一个urls.py文件以避免出错。

from django.contrib import admin
from django.urls import path, include

url_patterns = [
    path('admin/', admin.site.urls),
    path('', include('account.urls')),
]
Enter fullscreen mode Exit fullscreen mode

编写单元测试

编写单元测试是软件开发的基础环节,Django 提供了一个全面的测试框架来简化这一过程。这是 Django 中最常见的测试形式。我们将重点关注视图的测试。
我们的views.py代码如下:

from django.http import HttpResponse

    def hello_world(request):
        """A simple view that returns a string "Hello, world!""""
        return HttpResponse("Hello, world!")

    def add_numbers(request):
        """A view that returns the sum of two numbers."""
        if request.method == 'POST':
            num1 = int(request.POST.get('num1'))
            num2 = int(request.POST.get('num2'))
            sum = num1 + num2
            return HttpResponse(f"The sum of {num1} and {num2} is {sum}.")
        else:
            return HttpResponse("Please submit the form to add two numbers.")

Enter fullscreen mode Exit fullscreen mode

在 Django 中,单元测试通常组织成测试用例类。我们创建一个继承自 Django 类的新类。单元测试用例将分别基于我们上面提到的两个函数django.test.TestCase 此之前,让我们更新一下应用程序。tests.pyhello_worldadd_numbers
urls.py

from django.urls import path
from . import views

app_name = 'accounts'

urlpatterns = [
    path('hello/', views.hello_world, name='hello_world'),
    path('add/', views.add_numbers, name='add_numbers'),
]
Enter fullscreen mode Exit fullscreen mode

这些函数的单元测试代码如下所示:

from django.test import TestCase
    from django.urls import reverse

    class HelloWorldViewTest(TestCase):
        def test_hello_world(self):
            url = reverse('accounts:hello_world')
            response = self.client.get(url)
            self.assertEqual(response.status_code, 200)
            self.assertEqual(response.content.decode(), "Hello, world!")

    class AddNumbersViewTest(TestCase):
        def test_add_numbers_get(self):
            url = reverse('accounts:add_numbers')
            response = self.client.get(url)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, "Please submit the form to add two numbers.")

        def test_add_numbers_post(self):
            url = reverse('accounts:add_numbers')
            data = {'num1': '5', 'num2': '3'}
            response = self.client.post(url, data)
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, "The sum of 5 and 3 is 8.")
Enter fullscreen mode Exit fullscreen mode

为了确保测试能够运行并查看结果,我们使用以下命令python manage.py test,结果如下:

测试运行截图。

此过程会创建一个测试数据库,然后将其销毁。

编写集成测试

在 Django 的 Web 开发中,集成测试涉及测试应用程序各个部分之间的协作,例如视图、模型、模板和数据库。

对于我们的集成测试,我们将创建一个用于models.py测试的模型。

 from django.db import models

    class Name(models.Model):
        """A name model."""
        name = models.CharField(max_length=100)
        description = models.TextField()

        def __str__(self):
            return self.name
Enter fullscreen mode Exit fullscreen mode

我们的程序views.py会返回数据库中已有的姓名列表。

def name_list(request):
    """A view that returns a list of names."""
    names = Name.objects.all()
    return render(request, 'account/name_list.html', {'names': names})
Enter fullscreen mode Exit fullscreen mode

urls.py

from django.urls import path
from . import views

app_name = 'accounts'

urlpatterns = [
    path('names/', views.name_list, name='name_list'),
]

Enter fullscreen mode Exit fullscreen mode

我们的集成测试将如下tests.py

from django.test import TestCase, Client
    from django.urls import reverse
    from .models import Name

    class NameIntegrationTest(TestCase):
        def setUp(self):
            self.client = Client()
            self.url = reverse('accounts:name_list')

        def test_name_list_integration(self):
            # Create test data
            Name.objects.create(name='John', description='John Doe')
            Name.objects.create(name='Jane', description='Jane Smith')

            # Send a GET request to the URL
            response = self.client.get(self.url)

            # Assert the response status code and content
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'John')
            self.assertContains(response, 'Jane')

Enter fullscreen mode Exit fullscreen mode

值得注意的是,集成测试是对单元测试的补充,单元测试侧重于单独测试各个单元或组件。这两种测试对于确保软件应用程序的整体质量和可靠性都至关重要。

编写功能测试

功能测试,也称为端到端测试或验收测试,是一种从用户角度验证应用程序功能的软件测试。在 Django 中,功能测试模拟用户与应用程序的交互,并验证预期行为。本文将以我们之前提供的示例为例,使用 Selenium 在我们的项目models.pyviews.py创建urls.py一个功能测试。tests.py

Selenium是一个常用的开源框架,用于自动化网页浏览器操作。它提供了一系列工具和库,用于与网页浏览器交互并自动化浏览器操作,例如点击按钮、填写表单和浏览网页。它还支持多种编程语言, Python就是其中之一。
tests.py

from django.test import LiveServerTestCase
from selenium import webdriver
from .models import Name
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By

class NameFunctionalTest(LiveServerTestCase):
    def setUp(self):
        self.selenium = webdriver.Chrome()
        super().setUp()

    def tearDown(self):
        self.selenium.quit()
        super().tearDown()

    def test_name_list_functional(self):
        # Create test data
        Name.objects.create(name='John', description='John Doe')
        Name.objects.create(name='Jane', description='Jane Smith')

        # Simulate user interactions using Selenium
        self.selenium.get(self.live_server_url + '/names/')
        self.assertIn('Name List', self.selenium.title)
        names =self.selenium.find_elements(By.TAG_NAME, 'li')
        self.assertEqual(len(names), 2)
        self.assertEqual(names[0].text, 'John - John Doe')
        self.assertEqual(names[1].text, 'Jane - Jane Smith')

        # Simulate the page returns a 200
        self.assertEqual(self.selenium.title, 'Name List')
Enter fullscreen mode Exit fullscreen mode

测试命令运行后,Chrome 浏览器会迅速弹出并执行测试。

测试覆盖率和报告

测试覆盖率衡量的是测试套件对代码进行测试的程度。测试覆盖率对于确保软件的质量和可靠性至关重要。

Django 提供了多种用于测量测试覆盖率和生成报告的工具。其中一个常用的工具是 tsrc coverage.py,这是一个 Python 库,可以跟踪测试运行期间哪些代码部分被执行。

coverage.py在 Django 中使用它来进行测试覆盖率和报告,请按照以下步骤操作。

1.使用 pip 安装 coverage,运行以下命令

pip install coverage
Enter fullscreen mode Exit fullscreen mode

2.使用以下coverage命令运行测试并设置覆盖率

coverage run manage.py test
Enter fullscreen mode Exit fullscreen mode

3.测试运行完毕后,我们可以使用以下coverage report命令生成覆盖率报告。该命令会在终端中显示覆盖率摘要:

coverage report
coverage html # to generate an HTML report that is well detailed
Enter fullscreen mode Exit fullscreen mode

要自定义代码覆盖率,.coveragerc可以在 Django 项目的根目录下创建一个配置文件。例如,我的代码的测试覆盖率如下:

.coveragc 目录的屏幕截图

测试夹具和模拟

测试夹具和模拟是软件测试中的重要技术,它们有助于创建受控环境并隔离依赖关系,从而确保可靠和可预测的测试结果。

文本固定装置

测试夹具是一组预定义的数据、配置或状态,需要在运行测试之前设置好。它们有助于为测试创建一个一致且已知的起点,使我们能够重现特定的条件和行为。在 Django 中,我们可以使用测试夹具将数据加载到测试数据库中。

要创建测试数据文件,首先需要创建一个 JSON 文件来定义要使用的测试数据。例如,我们可以创建一个sample.json包含以下条目的文件:

[
  {
    "name": "Herlet Skim",
    "description": "A random person that exists out of nowhere but has a pretty interesting life."
  },
  {
    "name": "John Doe",
    "description": "A fictional character who is often used as a placeholder name."
  },
  {
    "name": "Jane Doe",
    "description": "A fictional character who is often used as a placeholder name for a woman."
  },
  {
    "name": "Sherlock Holmes",
    "description": "A fictional detective created by Sir Arthur Conan Doyle."
  },
  {
    "name": "Dr. Watson",
    "description": "A fictional doctor and the partner of Sherlock Holmes."
  }
]
Enter fullscreen mode Exit fullscreen mode

有了测试文件后,我们可以使用测试用例的属性sample.json来加载测试数据。通过在属性中指定测试数据文件,Django 会在运行测试方法之前加载该文件中定义的测试数据。fixturesfixtures

from django.test import TestCase

class MyTestCase(TestCase):
    fixtures = ['sample.json']

    def test_something(self):
        # Test logic here 
Enter fullscreen mode Exit fullscreen mode

嘲讽

另一方面,模拟(Mocking)是指用测试专用版本替换真实对象或函数,这些测试版本能够模拟它们的行为。在 Python/Django 中,该unittest.mock模块提供了强大的模拟功能。

要开始模拟,我们首先导入mock模块。

from unittest.mock import Mock
Enter fullscreen mode Exit fullscreen mode

利用我们之前从models.pyviews.py和中获得的数据urls.py,我们创建了一个新的tests.py用于模拟。

from django.test import TestCase, RequestFactory
from unittest.mock import Mock, patch
from .models import Name
from .views import name_list

class NameListViewTest(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def test_name_list_view(self):
        # Create some sample Name objects
        Name.objects.create(name='John Doe', description='Description 1')
        Name.objects.create(name='Jane Smith', description='Description 2')

        # Create a mock request object
        request = self.factory.get('/names/')

        # Create a mock queryset for the Name objects
        mock_queryset = Mock(spec=Name.objects.all())
        mock_queryset.return_value = [
            Mock(name='John Doe', description='Description 1'),
            Mock(name='Jane Smith', description='Description 2')
        ]

        # Patch the Name.objects.all() method to return the mock queryset
        with patch('account.views.Name.objects.all', mock_queryset):
            # Call the name_list view
            response = name_list(request)

        # Assert that the response has the expected status code
        self.assertEqual(response.status_code, 200)

        # Assert that the response contains the expected data
        self.assertContains(response, 'John Doe')
        self.assertContains(response, 'Jane Smith')

Enter fullscreen mode Exit fullscreen mode

测试最佳实践

在测试方面,遵循最佳实践可以显著提高测试流程的有效性和效率。以下是一些值得考虑的最佳实践:

1. 首先制定测试策略:定义一个清晰的测试策略,概述软件测试的目标、目的和方法。确定要执行的测试类型(单元测试、集成测试等),确定测试范围,并制定测试覆盖率的指导原则。

2. 编写可测试的代码:设计代码时要考虑测试的难易程度。遵循 SOLID 和 DRY 等原则,编写模块化、解耦且可重用的代码。将业务逻辑与表示层和外部依赖项分离,这样可以更轻松地进行单元测试。

3. 遵循 AAA 模式:编写单元测试时,应使用 Arrange-Act-Assert (AAA) 模式来组织测试代码。首先组织测试数据,然后设置必要的前提条件,接着对被测代码执行操作,最后断言测试结果或行为是否符合预期。

4. 测试边界情况和边缘情况:确保测试涵盖各种场景,包括边界情况和边缘情况。测试输入值的最小值和最大值、空值或null值,以及任何可能影响代码行为的特殊情况。

5. 监控代码覆盖率:测量并监控代码覆盖率,确保测试能够充分覆盖代码库。力求实现高代码覆盖率,以增强对软件可靠性和正确性的信心。

6. 维护和更新测试:确保测试与代码库的变更保持同步。当应用程序发生更改时,应相应地审查和更新测试。过时的测试可能会产生误报或漏报,从而导致结果不可靠。

测试自动化和持续集成

测试自动化和持续集成是软件开发中的关键实践,有助于提高效率、质量和可靠性。让我们更详细地探讨这两个概念。

测试自动化

这包括使用工具和脚本来自动化测试的执行,从而减少人工操作,并实现更快、更频繁的测试。它涉及编写代码来自动化测试用例的设置、执行和验证。测试自动化的一些优势包括:

1. 效率提升:自动化测试的执行速度比手动测试快得多,从而可以更快地获得软件质量的反馈。

2. 提高测试覆盖率:通过测试自动化,可以在较短的时间内运行更多测试,从而更容易实现较高的测试覆盖率。

3. 与 CI/CD 集成:自动化测试可以无缝集成到 CI/CD 管道中,从而实现持续测试和更快的软件交付。

4. 一致性:自动化测试确保测试执行的一致性,并消除手动测试过程中可能出现的人为错误。

Django 常用的测试自动化框架和工具包括unittestpytestSelenium、用于浏览器自动化的WebDriver以及 Django 内置的测试框架。

持续集成(CI)

持续集成是一种开发实践,开发人员频繁地将代码更改合并到共享代码库中。CI 流程包括每次代码提交后自动构建和测试软件。CI 的一些关键方面包括:

1. 自动化构建: CI 系统会在每次代码提交时自动构建软件,确保代码库保持一致且功能完备的状态。

2. 自动化测试:包括单元测试、集成测试甚至 UI 测试在内的自动化测试,都是持续集成 (CI) 流程的一部分。这确保代码变更不会引入回归问题或破坏现有功能。3
. 与版本控制集成: CI 系统与 Git 等版本控制系统集成,使其能够监控代码变更并自动触发构建和测试流程。4
. 部署就绪: CI 有助于确保软件始终处于可部署状态。如果构建和测试均成功通过,则软件即可部署。

常用的 CI 工具包括 Jenkins、Travis CI、CircleCI 和 GitLab CI/CD。

通过结合测试自动化和持续集成,我们可以建立稳健高效的软件开发流程。自动化测试还能快速反馈代码变更,及早发现问题,并提升整体软件质量。

结论

测试是软件开发周期中的一个重要环节,因为它有助于保证代码质量、可靠性和正确性。

通过在 Django 项目中采用全面的测试方法,我们可以提高应用程序的稳定性、可维护性和整体质量。

它帮助开发者交付符合用户期望、符合规范并能经受住实际使用场景的产品。

通过将测试实践融入到开发工作流程中,软件团队可以实现更高的质量保证和客户满意度。

文章来源:https://dev.to/ifihan/testing-in-django-26e5