三十二、实战演练之接口自动化平台的模型创建、项目管理接口设计

文章详细描述了使用Django框架构建项目管理应用的过程,包括项目、测试计划、测试报告和bug管理的应用模型设计,以及相关的接口设计。模型涵盖了项目信息、测试环境、接口、bug状态等关键数据结构。此外,还介绍了项目创建、删除、修改等接口的API设计。
摘要由CSDN通过智能技术生成

1. 模型编写

根据项目需求分析和数据库设计,我们创建项目应用,测试计划应用,测试报告应用,bug应用:

django-admin startapp projects
django-admin startapp testplans
django-admin startapp reports
django-admin startapp bugs

注意在配置文件中注册应用。然后分别创建对应的模型如下:

(1)项目应用模型

from django.db import models
from utils.models import BaseModel


class Project(models.Model):
    """项目表"""
    name = models.CharField(max_length=50, help_text='项目名称', verbose_name='项目名')
    leader = models.CharField(max_length=50, help_text='负责人', verbose_name='负责人', default='')
    create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'project'
        verbose_name = "项目表"
        verbose_name_plural = verbose_name


class TestEnv(models.Model):
    """测试环境表"""
    name = models.CharField(max_length=150, help_text='环境名称', verbose_name='环境名称')
    # 一个项目有多个测试环境,一个环境只属于一个项目
    # models.CASCADE 删除项目的时候,就把相关环境同步删除。
    project = models.ForeignKey(Project, on_delete=models.CASCADE, help_text='项目id', verbose_name='项目id',
                                related_name='test_envs')  # 反向字段名
    global_variable = models.JSONField(help_text='全局变量', verbose_name='全局变量', default=dict, null=True,
                                       blank=True)
    debug_global_variable = models.JSONField(help_text='debug模式全局变量', verbose_name='debug模式全局变量',
                                             default=dict, null=True, blank=True)
    db = models.JSONField(help_text='数据库配置', verbose_name='数据库配置', default=list, null=True, blank=True)
    host = models.CharField(help_text='base_url地址', verbose_name='base_url地址', max_length=100, blank=True)
    headers = models.JSONField(help_text='请求头', verbose_name='请求头', default=dict, null=True, blank=True)
    global_func = models.TextField(help_text='用例工具文件', verbose_name='用例工具文件',
                                   default=open('utils/global_func.py', 'r', encoding='utf-8').read(), null=True,
                                   blank=True)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'tb_test_env'
        verbose_name = "测试环境表"
        verbose_name_plural = verbose_name


class Interface(models.Model):
    """接口表"""
    CHOICES = [
        ('1', '项目接口'),
        ('2', '外部接口')
    ]
    project = models.ForeignKey(Project, on_delete=models.CASCADE, help_text='项目id',
                                verbose_name='项目id',
                                related_name='interfaces')
    name = models.CharField(max_length=50, help_text='接口名称', verbose_name='接口名')
    url = models.CharField(max_length=200, help_text='接口路径', verbose_name='接口路径')
    method = models.CharField(max_length=50, help_text='请求方法', verbose_name='请求方法')
    type = models.CharField(verbose_name='接口类型', help_text='接口类型',
                            max_length=40, choices=CHOICES, default='1')

    def __str__(self):
        return self.url

    class Meta:
        db_table = 'tb_interface'
        verbose_name = '接口表'
        verbose_name_plural = verbose_name

(2)bug应用模型

from django.db import models


class Bug(models.Model):
    """Bug模型"""
    CHOICES = [
        ('未处理', '未处理'),
        ('处理中', '处理中'),
        ('处理完', '处理完'),
        ('无效bug', '无效bug'),
    ]
    # 项目
    project = models.ForeignKey('projects.Project', on_delete=models.CASCADE, help_text='项目id', verbose_name='项目id')
    # 接口
    interface = models.ForeignKey('projects.Interface', on_delete=models.CASCADE, verbose_name='接口', help_text='接口')
    # bug描述
    desc = models.TextField(verbose_name='bug描述', help_text='bug描述', max_length=3000, blank=True)
    # bug基本信息 (请求头 请求体 请求方式 响应结果)
    info = models.JSONField(verbose_name='bug信息', help_text='bug信息', default=dict, blank=True)
    # bug状态 (待提交,已提交,处理中,关闭,无效bug)
    status = models.CharField(verbose_name='bug状态', help_text='bug状态', max_length=40, choices=CHOICES,
                              default='未处理')
    # bug提交者
    user = models.CharField(verbose_name='提交者', help_text='提交者', max_length=40, default='', blank=True)
    create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)

    class Meta:
        db_table = 'tb_bug'
        verbose_name = 'bug表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.id


class BugHandle(models.Model):
    """bug操作记录表"""
    bug = models.ForeignKey('Bug', on_delete=models.CASCADE, verbose_name='bug_id', help_text='bug_id')
    create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
    handle = models.TextField(verbose_name='处理操作', help_text='处理操作', blank=True)
    update_user = models.CharField(verbose_name='更新用户', help_text='更新用户', max_length=32, blank=True)

    class Meta:
        db_table = 'tb_bug_handle'
        verbose_name = 'bug操作记录表'
        verbose_name_plural = verbose_name

(3)测试报告应用模型

from django.db import models


class Record(models.Model):
    """运行记录表"""
    create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
    plan = models.ForeignKey('testplans.TestPlan', help_text='执行计划', verbose_name='执行计划',
                             on_delete=models.PROTECT, related_name='records')
    all = models.IntegerField(help_text='用例总数', verbose_name='用例总数', blank=True, default=0)
    success = models.IntegerField(help_text='成功用例', verbose_name='成功用例', blank=True, default=0)
    fail = models.IntegerField(help_text='失败用例', verbose_name='失败用例', blank=True, default=0)
    error = models.IntegerField(help_text='错误用例', verbose_name='错误用例', blank=True, default=0)
    pass_rate = models.CharField(help_text='执行通过率', verbose_name='执行通过率', max_length=100, blank=True,
                                 default=0)
    tester = models.CharField(help_text='执行者', verbose_name='执行者', max_length=100, blank=True)
    test_env = models.ForeignKey('projects.TestEnv', help_text='测试环境', verbose_name='测试环境',
                                 on_delete=models.PROTECT)
    statue = models.CharField(help_text='执行状态', verbose_name='执行状态', max_length=100)

    def __str__(self):
        return str(self.id)

    class Meta:
        db_table = 'tb_record'
        verbose_name = '运行记录表'
        verbose_name_plural = verbose_name


class Report(models.Model):
    """测试报告"""
    info = models.JSONField(help_text='测试报告', verbose_name='测试报告', default=dict, blank=True)
    record = models.OneToOneField('Record', help_text='测试记录', verbose_name='测试记录 ', on_delete=models.PROTECT)

    def __str__(self):
        return str(self.id)

    class Meta:
        db_table = 'tb_report'
        verbose_name = '报告表'
        verbose_name_plural = verbose_name

(4)测试计划应用模型

from django.db import models


class TestPlan(models.Model):
    """测试计划"""
    create_time = models.DateTimeField(verbose_name='创建时间', help_text='创建时间', auto_now_add=True)
    name = models.CharField(verbose_name='计划名', help_text='计划名', max_length=150)
    project = models.ForeignKey('projects.Project', verbose_name='项目id', help_text='项目id', on_delete=models.CASCADE,
                                related_name='test_plan')
    scenes = models.ManyToManyField('TestScene', help_text='包含的测试场景', verbose_name='包含的测试场景', blank=True)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'tb_test_plan'
        verbose_name = '测试计划表'
        verbose_name_plural = verbose_name


class TestScene(models.Model):
    """测试场景/测试套件"""
    # 一系列有顺序的测试用例
    project = models.ForeignKey('projects.Project', help_text='所属项目', verbose_name='项目名称',
                                on_delete=models.PROTECT, related_name='test_scenes')
    name = models.CharField(max_length=50, help_text='测试场景名', verbose_name='测试场景名')

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'tb_test_scene'
        verbose_name = "测试场景"
        verbose_name_plural = verbose_name


class SceneData(models.Model):
    """场景/套件数据"""
    step = models.ForeignKey('TestStep', help_text='步骤', verbose_name='步骤',
                             on_delete=models.PROTECT)
    scene = models.ForeignKey(TestScene, help_text='场景', verbose_name='场景', on_delete=models.PROTECT)
    sort = models.IntegerField(help_text='执行顺序', verbose_name='执行顺序',
                               blank=True)

    def __str__(self):
        return str(self.id)

    class Meta:
        db_table = 'tb_scene_data'
        verbose_name = "场景步骤"
        verbose_name_plural = verbose_name


setup_script = """
# 前置脚本(python):
# global_tools:全局工具函数
# data:用例数据
# env: 局部环境

# ENV: 全局环境
# db: 数据库操作对象
"""
teardown_script = """
# 后置脚本(python):
# global_tools:全局工具函数
# data:用例数据
# response:响应对象response
# env: 局部环境
# ENV: 全局环境
# db: 数据库操作对象
"""


class TestStep(models.Model):
    """用例表"""
    title = models.CharField(max_length=50, help_text='用例名称', verbose_name='用例名')
    interface = models.ForeignKey('projects.Interface', on_delete=models.CASCADE, help_text='接口', verbose_name='接口')
    headers = models.JSONField(help_text='请求头', verbose_name='请求头', default=dict, blank=True)
    request = models.JSONField(help_text='请求信息', verbose_name='请求信息', default=dict, blank=True)
    file = models.JSONField(help_text='上传的文件参数', verbose_name='上传的文件', default=list, blank=True)
    setup_script = models.TextField(help_text='前置脚本', verbose_name='前置脚本', default=setup_script, blank=True)
    teardown_script = models.TextField(help_text='后置脚本', verbose_name='用例后置脚本 ', default=teardown_script,
                                       blank=True)

    def __str__(self):
        return self.title

    class Meta:
        db_table = 'tb_test_step'
        verbose_name = "测试步骤表"
        verbose_name_plural = verbose_name

二、项目管理接口设计

(1)项目创建

接口名称: /projects/

请求方式: POST

参数格式: JSON

请求参数:

参数

变量名

类型

说明

是否必传

项目名称

name

字符串

项目名称

项目负责人

leader

字符串

项目负责人

请求示例:

json格式参数

{

"name": "前程贷",

"leader": "心蓝"

}

返回示例

响应状态码:201 响应数据:

{

"id": 1,

"create_time": "2022-07-12T21:59:57.606147+08:00",

"name": "ck12接口自动化",

"leader": "心蓝"

}

(2)删除项目

接口名称: /projects/项目ID/

请求方式: DELETE

参数格式: 路径参数

请求参数:

返回示例

响应状态码:204

响应数据:无

(3)修改项目

接口名称: /projects/项目ID/

请求方式: PUT/PATCH

参数格式: JSON

请求参数:

参数

变量名

类型

说明

是否必传

项目名称

name

字符串

项目名称

PUT请求必传

项目负责人

leader

字符串

项目负责人

PUT请求必传

请求示例:

json格式参数

{

"name": "前程贷",

"leader": "心蓝"

}

返回示例

响应状态码:200 响应数据:

{

"id": 1,

"create_time": "2022-07-12T21:59:57.606147+08:00",

"name": "ck12接口自动化",

"leader": "心蓝"

}

(4)查看项目列表

接口名称:

请求方式: GET

参数格式: 无

请求参数: 无

返回示例

响应状态码:200 响应数据:

[{

id": 1,

"create_time": "2022-07-12T21:59:57.606147+08:00",

"name": "ck12接口自动化",

"leader": "心蓝"

}]

(5)查看项目

接口名称:

请求方式: GET

参数格式: 路径参数

请求参数:

返回示例

响应状态码:200 响应数据:

{
  "id": 1,
  "create_time": "2022-07-12T21:59:57.606147+08:00",
  "name": "ck12接口自动化",
  "leader": "心蓝",
  "info": [
    {
      "name": "执行环境",
      "value": 0
    },
    {
      "name": "测试场景",
      "value": 0 	},
    {
      "name": "测试计划",
      "value": 0 	},
    {
      "name": "接口数量",
      "value": 0 	},
    {
      "name": "定时任务",
      "value":0
    },
    {
      "name": "执行记录",
      "value": 0
    }],
  "bugs":[
    {
      "name": "未处理bug",
      "value": 0
    },
    {
      "name": "处理中bug",
      "value": 0
    },
    {
      "name": "处理完bug",
      "value": 0
    },
    {
      "name": "无效bug",
      "value": 0
    }
  ]

(6)后端代码

① 新增模型方法

因为在获取项目详情时需要统计对应的数据,所以我们再项目模型中新增如下方法:

class Project(models.Model):
    """项目表"""
    name = models.CharField(verbose_name="项目名", help_text="项目名称", max_length=50)
    leader = models.CharField(verbose_name="负责人", help_text="项目负责人", max_length=50, default='')
    create_time = models.DateTimeField(verbose_name="创建时间", help_text="", auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        db_table = "project"
        verbose_name = "项目表"
        verbose_name_plural = verbose_name

    def info(self):
        """返回项目的统计信息"""
        return [
            {'name': '执行环境', 'value': self.test_envs.count()},
            {'name': '测试场景', 'value': self.test_scenes.count()},
            {'name': '测试计划', 'value': self.test_plan.count()},
            {'name': '接口数量', 'value': self.interfaces.count()},
            {'name': '定时任务', 'value': 0},
            {'name': '执行记录', 'value': Record.objects.filter(plan__name=self.name).count()},
        ]

    def bugs(self):
        """返回bugs的统计信息"""
        return [
            {'name': '未处理', 'value': self.bug_set.filter(status='未处理').count()},
            {'name': '处理中', 'value': self.bug_set.filter(status='处理中').count()},
            {'name': '处理完', 'value': self.bug_set.filter(status='处理完').count()},
            {'name': '无效bug', 'value': self.bug_set.filter(status='无效bug').count()},
        ]

② 序列化器

在projects应用中创建serializers.py 模块,编写代码如下:

class ProjectSerializer(serializers.ModelSerializer):
    """项目序列化器"""

    # 注意info和bugs是对象方法
    class Meta:
        model = Project
        fields = ['id', 'create_time', 'name', 'leader', 'info', 'bugs']

③ 视图

class ProjectViewSet(ModelViewSet):
    """项目视图集"""
    serializer_class = ProjectSerializer
    queryset = Project.objects.all()
    permission_classes = [IsAuthenticated, IsLeaderOrReadOnly]
    
    # 还可以过滤一下查询集,实现特定的人群看到特定的项目
    def get_queryset(self):
        return Project.objects.filter(leader=self.request.user)

④ 路由

from rest_framework.routers import DefaultRouter

from . import views

router = DefaultRouter()
router.register('projects', views.ProjectViewSet)
urlpatterns = router.urls

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值