Skip to content

测试规范

概述

项目采用 Django 内置测试框架(基于 unittest),支持单元测试和集成测试。测试使用 python manage.py test 命令运行。

测试体系

  1. 单元测试(Unit):验证单个函数/方法的逻辑正确性
  2. 集成测试(Integration):验证模块间协作、真实数据库操作

目录结构

tests/
├── test_models.py           # 模型测试
├── test_services.py         # Service 层测试
├── test_views.py            # View 层测试
├── test_forms.py            # Form 层测试
└── test_utils.py            # 工具函数测试

或按应用组织:

application/example/
├── models.py
├── services.py
├── views.py
├── forms.py
└── tests.py                 # 该应用的测试

Django TestCase 示例

模型测试

python
from django.test import TestCase
from application.example.models import Example


class ExampleModelTest(TestCase):
    """案例模型测试"""

    def test_create_example(self):
        """测试创建案例"""
        example = Example.objects.create(
            name='测试案例',
            type=1,
            status=1,
            sort=1,
            create_user='admin'
        )
        self.assertIsNotNone(example.id)
        self.assertEqual(example.name, '测试案例')
        self.assertFalse(example.is_delete)

    def test_soft_delete(self):
        """测试软删除"""
        example = Example.objects.create(
            name='待删除案例',
            type=1,
            status=1,
            sort=1,
        )
        example.is_delete = True
        example.save()

        # 验证软删除后查询不到
        self.assertFalse(
            Example.objects.filter(is_delete=False, id=example.id).exists()
        )

        # 验证包含已删除记录可以查到
        self.assertTrue(
            Example.objects.filter(id=example.id).exists()
        )

Service 层测试

python
from django.test import TestCase, RequestFactory
from application.example.services import get_example_page, add_example


class ExampleServiceTest(TestCase):
    """案例 Service 层测试"""

    def setUp(self):
        """测试前准备"""
        self.factory = RequestFactory()
        # 创建测试数据
        Example.objects.create(name='案例1', type=1, status=1, sort=1)
        Example.objects.create(name='案例2', type=1, status=1, sort=2)

    def test_get_example_page(self):
        """测试分页查询"""
        request = self.factory.get('/example/page', {'pageNo': 1, 'pageSize': 10})
        result = get_example_page(request)
        # 验证返回格式
        self.assertEqual(result.status_code, 200)

    def test_get_example_page_with_filter(self):
        """测试带筛选条件的分页查询"""
        request = self.factory.get('/example/page', {'name': '案例1'})
        result = get_example_page(request)
        self.assertEqual(result.status_code, 200)

View 层测试

python
from django.test import TestCase, Client
from application.example.models import Example


class ExampleViewTest(TestCase):
    """案例 View 层测试"""

    def setUp(self):
        """测试前准备"""
        self.client = Client()
        # 创建测试数据
        Example.objects.create(name='案例1', type=1, status=1, sort=1)

    def test_page_without_login(self):
        """测试未登录访问分页接口"""
        response = self.client.get('/example/page')
        # 未登录应返回 401 或重定向
        self.assertIn(response.status_code, [401, 302])

    def test_page_with_login(self):
        """测试登录后访问分页接口"""
        # 模拟登录(需根据实际认证方式调整)
        self.client.force_login(user=User.objects.first())
        response = self.client.get('/example/page')
        self.assertEqual(response.status_code, 200)

Form 层测试

python
from django.test import TestCase
from application.example.forms import ExampleForm


class ExampleFormTest(TestCase):
    """案例 Form 层测试"""

    def test_valid_form(self):
        """测试有效表单"""
        data = {
            'name': '测试案例',
            'type': 1,
            'status': 1,
            'sort': 1,
        }
        form = ExampleForm(data)
        self.assertTrue(form.is_valid())

    def test_invalid_form_missing_name(self):
        """测试缺少必填字段"""
        data = {
            'type': 1,
            'status': 1,
            'sort': 1,
        }
        form = ExampleForm(data)
        self.assertFalse(form.is_valid())
        self.assertIn('name', form.errors)

    def test_invalid_form_type_out_of_range(self):
        """测试类型值超出范围"""
        data = {
            'name': '测试案例',
            'type': 99,  # 超出范围
            'status': 1,
            'sort': 1,
        }
        form = ExampleForm(data)
        self.assertFalse(form.is_valid())
        self.assertIn('type', form.errors)

测试命名规范

类型文件命名函数命名
模型测试test_*.pytest_*
Service 测试test_*.pytest_*
View 测试test_*.pytest_*
Form 测试test_*.pytest_*

函数命名规则

测试函数名应清晰描述被测行为:

  • test_create_example:验证创建案例
  • test_soft_delete:验证软删除
  • test_get_page_with_filter:验证带筛选的分页查询

运行命令

bash
# 运行所有测试
python manage.py test

# 运行指定应用的测试
python manage.py test application.example

# 运行指定测试文件
python manage.py test application.example.tests

# 运行指定测试类
python manage.py test application.example.tests.ExampleModelTest

# 运行指定测试方法
python manage.py test application.example.tests.ExampleModelTest.test_create_example

# 显示详细输出
python manage.py test -v 2

# 运行测试并显示覆盖率
python manage.py test --parallel

测试数据库

Django 测试框架会自动创建测试数据库(命名为 test_{DATABASE_NAME}),测试完成后自动销毁。

测试数据库配置

  • 测试数据库与生产数据库完全隔离
  • 每个测试方法运行在独立事务中,测试结束后自动回滚
  • 使用 TestCase 而非 TransactionTestCase 可获得更好的性能

测试覆盖率

bash
# 安装覆盖率插件
pip install coverage

# 运行测试并生成覆盖率报告
coverage run --source='application' manage.py test

# 查看报告
coverage report

# 生成 HTML 报告
coverage html

覆盖率目标

  • Model 层:90%+
  • Service 层:80%+
  • View 层:70%+

总结

测试规范使用 Django 内置测试框架,支持模型、Service、View、Form 各层测试。测试文件命名 test_*.py,函数命名 test_*。使用 python manage.py test 运行测试,测试数据库自动创建和销毁。建议使用 coverage 工具监控测试覆盖率。

小蚂蚁云团队 · 提供技术支持