自动化测试平台(九):用例概览页开发和子级菜单的使用

x33g5p2x  于2021-12-28 转载在 其他  
字(5.6k)|赞(0)|评价(0)|浏览(573)

一、前言

上一章我们完成了列表组件公共化封装和项目管理功能的实现,这一章将实现用例概览页功能,用于测试项目的测试情况的一个统计展示。

为了开发效率,很多类型都是用any来定义的,小伙伴可以自己进行完善

完整教程地址:《从0搭建自动化测试平台》

项目在线演示地址:http://121.43.43.59/ (帐号:admin 密码:123456)

本章内容实现效果如下:

二、题外话

之前有小伙伴反应多次点击会出现消息重复弹出的情况,如下图所示:

我们可以修改antd的message组件的配置来设置它的显示最大数量、位置、持续时间等,例如下面的代码:

import { message } from 'antd';
 message.config({
    top: 100, //位置
    duration: 2,//持续时间
    maxCount: 1,//显示的最大数量
  });

app.tsx中加入上述代码即可。

三、后端用例模块接口

1. 项目文件创建及表模型建立

1)首先在代码项目下执行创建用例模块的命令:

django-admin startapp cases

后面用例相关(用例模块、报告等)都会放到这里面进行管理。

2)建立用例模块表,表模型如下:

from django.db import models
from comFunc.comModel import ComModel
from project.models import Project

class Module(ComModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name="模块名称")
    status0 = models.IntegerField(default=0, verbose_name="等待执行")
    status1 = models.IntegerField(default=0, verbose_name="执行失败")
    status2 = models.IntegerField(default=0, verbose_name="正在执行")
    status3 = models.IntegerField(default=0, verbose_name="执行完成(接口用例特有状态)")
    status4 = models.IntegerField(default=0, verbose_name="执行通过")
    status = models.IntegerField(verbose_name="模块状态")
    parent = models.ForeignKey(to='self', verbose_name="父模块", null=True, on_delete=models.DO_NOTHING)
    project = models.ForeignKey(to=Project, on_delete=models.DO_NOTHING, default=1, verbose_name="关联的项目id")
    type = models.IntegerField(verbose_name="模块类型")

    class Meta:
        verbose_name = '用例模块'
        db_table = 'module'

类似的增删改查代码根据之间的教学进行CURD开发即可。

2. 概览列表接口开发

1)概览列表接口的功能是将项目下模块不同状态数量进行查询并汇总,没有模块的项目默认全部为0,我们可以先查项目表,然后使用django里orm的反向查询它的模块数据,没有模块的全部设为0即可,代码如下:

def case_overview(request):
    """ 用例概览情况 """
    case_type = request.query_params['type']  # 代表查询UI还是API用例概览情况
    projects = Project.objects.filter(type=case_type)
    value_fields = {f'status{i}': Sum(f'status{i}') for i in range(5)}
    value_fields.update(
        {'project_name': F('project__name'), 'project_status': F('project__status'),
         'total': F('status0') + F('status1') + F('status2') + F('status3') + F('status4')})
    res_data = []
    for project in projects:
        data = project.module_set.filter(parent_id=None).values('project_id').annotate(**value_fields).first()
        res_data.append(data or {**{f'status{i}': 0 for i in range(5)},
                                 **{'project_id': project.id, 'project_status': project.status,
                                    'project_name': project.name, 'total': 0}})
    return Response(data=res_data)

这样的实现性能上会查一些,因为每个项目都会进行一次模块的反查,这样每多一个项目就会多一次sql的查询。
更好的做法是直接将两张表的数据都查出来,然后代码中做组合,小伙伴们可以自己动手去实现。

2)按照上面实现的概览接口使用时会报错,这是因为返回的是queryset类似list的这种类型的数据,我们之前开发的中间件没有适配这种情况,需要修改中间件来进行兼容,修改后的中间件核心代码如下:

if res_data is not None:
       if isinstance(res_data, dict):
           if 'code' not in res_data:
               if 'data' in res_data:
                   response.data.update({'code': status.HTTP_200_OK, 'msg': ''})
               else:  # delete请求返回的数据没有data,所以下面的逻辑需要单独处理
                   response.data = {'code': status.HTTP_200_OK,
                                    'msg': res_data.pop('msg', ''),
                                    'data': res_data}
       elif isinstance(res_data, (list, QuerySet)):
           response.data = {'code': status.HTTP_200_OK, 'data': res_data, 'msg': ''}

注:需要在头部引入QuerySet:

from django.db.models import QuerySet

四、前端页面

首先,还是执行创建cases页面模块的文件:

npx umi g page cases/index --typescript

1. 子级菜单

根据演示效果我们可以看到,用例管理是一个有子级的菜单。

这里我们只需要在.umirc.ts配置文件加入嵌套routes即可,代码如下:

{
          name: '用例管理',
          icon: 'case',
          path: '/case',
          routes: [
            {
              name: '自动化UI用例管理',
              path: '/case/uiCaseOverview',
              component: '@/pages/caseOverview',
            },
            {
              name: '自动化Api用例管理',
              path: '/case/apiCaseOverview',
              component: '@/pages/caseOverview',
            },
          ],
        },

这样修改完成后我们就能够在页面上看到如下的菜单效果了:

2. 概览页实现

概览页使用了antd栅格布局来排版,然后结合Card组件实现了如下的效果:

最后结合请求的路由地址不同给请求概览页接口带上不同的type参数,将其返回的数据按上述组件格式进行遍历添加,就能够实现最终的效果了:

完整index.tsx代码如下:

import React, { useState, useEffect } from 'react';
import { PROJECT_STATUS_TAG } from '@/globalEnum';
import { caseOverview } from '@/services/cases';
import { Card, Col, Spin, Tag, Button, Badge, message, Row } from 'antd';

const CaseOverview: React.FC = (props: any) => {
  const type = props.match.path === '/case/uiCaseOverview' ? 1 : 2;
  const [loading, setLoading] = useState<boolean>(true);
  const [cardItems, setcardItems] = useState<any>([]);
  useEffect(() => {
    caseOverview({ type: type }).then((res) => {
      const cards = res.data.map((item: any) => (
        <Col key={item.project_id} span={8}>
          <Card
            title={
              <div>
                <h3 style={{ fontWeight: 'bold', display: 'inline' }}>
                  {item.project_name}
                </h3>
                <Button
                  style={{ float: 'right' }}
                  onClick={() => message.warning('待实现')}
                >
                  管理UI元素
                </Button>
              </div>
            }
          >
            <Tag
              style={{ float: 'right', height: '2em' }}
              color={PROJECT_STATUS_TAG[item.project_status].color}
            >
              {PROJECT_STATUS_TAG[item.project_status].text}
            </Tag>

            <ul style={{ listStyleType: 'none', padding: 0 }}>
              <Badge status="error" text="用例失败数量:" />
              {item.status1}
              <li>
                <Badge status="default" text="等待执行数量:" />
                {item.status0}
              </li>
              <li>
                <Badge status="warning" text="正在执行数量:" />
                {item.status2}
              </li>
              <li>
                <Badge status="processing" text="执行完成数量:" />
                {item.status3}
              </li>
              <li>
                <Badge status="success" text="测试通过数量:" />
                {item.status4}
              </li>
            </ul>
            <h3 style={{ float: 'right' }}>用例总数量:{item.total}</h3>
          </Card>
        </Col>
      ));
      setcardItems(cards);
      setLoading(false);
    });
  }, []);
  return (
    <Spin spinning={loading}>
      <div
        style={{
          overflowX: 'hidden',
          overflowY: 'auto',
          height: 'calc(100vh - 100px)',
        }}
      >
        <Row gutter={[16, 16]}>{cardItems}</Row>
      </div>
    </Spin>
  );
};
export default React.memo(CaseOverview);

globalEnum.ts新增代码如下:

export const PROJECT_STATUS_TAG = {
  0: { text: '项目进行中', color: '#faad14' },
  1: { text: '项目已完成', color: '#52c41a' },
}; //代表请求列表

cases服务层接口请求代码如下:

import { request } from 'umi';

export function caseOverview(params: any) {
  return request<any>('/cases/overview', { params });
}

五、总结

这一章没有复杂的内容,基本都是重复的CURD。下一章节会正式开始自动化用例模块相关的教学和开发了。

平台在线演示地址:http://121.43.43.59/ (帐号:admin 密码:123456)

相关文章