借助vue-element-admin定制化构建测试平台

写在前面

这篇文章适用于使用过Vue和Django的同学,文章介绍如何搭建vue-element-admin框架,通过实例介绍,如何从vue-element-admin挑选适用于自己项目的页面,这样测试开发人员可以更加集中于测试需求的开发,文章最后介绍了处理队列的python库celery,用于异步执行任务。它将任务添加到Celery队列中,使应用程序可以继续执行其他操作,而不必等待任务完成。这个方法通常用于处理比较耗时的任务,以避免对应用程序的性能造成影响。


基础环境搭建

vue-element-admin框架介绍

Vue-Element-Admin是一个基于Vue和Element-UI实现的后台管理系统快速开发框架。该框架借助了Element-UI组件库以及Vue的数据驱动视图特性,极大地简化了后台管理系统的开发过程。
Vue-Element-Admin框架提供了大量的实现后台管理系统所需的通用组件和功能,例如路由管理、用户管理、权限管理等。同时,该框架还提供了多个主题风格、国际化以及Chrome调试工具等实用特性,为后台管理系统的开发提供了更多的扩展和自定义选项。
Vue-Element-Admin框架使用Webpack打包工具进行构建,并对Webpack的构建方式进行了优化,同时该框架还支持ES6、ES7的新特性,并提供了一系列的代码检查和格式化工具,以保证代码的质量和规范性。
GitHub地址:https://github.com/PanJiaChen/vue-element-admin
项目在线预览:https://panjiachen.gitee.io/vue-element-admin

vue-element-admin环境搭建

  1. 直接下载 https://gitee.com/constfiv/vue-element-admin-fix-install-problem,相比于https://github.com/PanJianChen/vue-element-admin.git的版本,这个版本好很多,npm intsall不会有各种依赖的问题,而且时间快很多
  2. 重装node,安装node低版本,我装的是12的版本 https://nodejs.org/zh-cn/download/releases/
  3. cmd -> npm install,大概几分钟时间
    在这里插入图片描述
  4. 输入npm run dev,项目成功启动
    在这里插入图片描述

vue-element-admin与Django集成

与真实环境使用Nginx相比,更建议将打包好的文件,放到DJango的Template目录下,方便调试
使用npm run build:prod 开始build包
在这里插入图片描述
打包后的文件放到Django项目目录下重命名为frontend
在这里插入图片描述
修改settings中TEMPLATES和STATICFILES_DIRS

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        ## 指向frontend
        'DIRS': [os.path.join(BASE_DIR, 'frontend')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
STATICFILES_DIRS = [
    ## 指向frontend/static
    os.path.join(BASE_DIR, "frontend/static")
]

配置路由,访问项目,结果如下
在这里插入图片描述

定制开发项目

平台开发方案制定

jenkins流水线构建是自动化测试的一个重要环节,如果自动化没有实现流水线,这个自动化不能算得上成功,但是很多企业jenkins没有对外开放,只有少数人有访问的权限,而且jenkins可能部署在多个服务器,没有办法将需要使用的job汇总在一起展示,需要登陆多个平台。同时jenkins显示自动化每个节点信息都很友好。鉴于需要使用python语言,所以最后确定利用vue实现前端界面,利用django实现后台服务,Python调用jenkins job 实现自动测试任务调度的方案。

平台开发实战

jenkins服务启动

首先确保本地搭建了jenkins服务,保证后端服务可以调通

  1. 确保本地已经搭建好了java的环境
  2. 去jenkins官网下载war包 https://www.jenkins.io/zh/download/
  3. 上传到linux上启动war包,并启动服务nohup java -jar jenkins.war --httpPort=8080 &
    在这里插入图片描述
  4. 注册账号并登陆
    在这里插入图片描述

jenkins和Django集成

开发过程中可以前后端同时进行最后集成在一起,本例先开发后端服务,保证需求可以实现

  1. 安装python调用jenkins的第三方库 pip install python-jenkins
  2. 新建app,并加入到setting中
  3. 编写调用jenkins的代码,并测试,如下展示了调用jenkins的部分代码
import time
import requests
import jenkins


class JenkinsClient(object):
    def __init__(self):
        self.jenkins_config = {
            "url": "http://120.25.253.110:8080/",
            "username": "*****1688",
            "password": "******5588"
        }
        self.jenkins_server = jenkins.Jenkins(**self.jenkins_config)

    def get_all_jobs(self):
        '''
        获取所有JOBS
        '''
        return self.jenkins_server.get_all_jobs()

    def get_job_info(self, job_name):
        return self.jenkins_server.get_job_info(job_name)
    
    
    def get_all_jobs_info(self):
        '''
        获取所有JOB信息
        '''
        jobs_list = []
        jobs = self.get_all_jobs()
        for job in jobs:
            jobs_dict = {}
            job_name = job.get('name')
            number = self.get_lastbuild_number(job_name)
            url, timestamp, result = self.get_build_job_info(job_name, number)
            test_total, tests_skip, tests_faild = self.get_job_testcase(job.get('url'), number)
            jobs_dict['build_job'] = job_name
            jobs_dict['build_url'] = url
            jobs_dict['build_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp / 1000))
            jobs_dict['build_number'] = number
            jobs_dict['build_result'] = result
            jobs_dict['testcase_total'] = test_total
            jobs_dict['testcase_skips'] = tests_skip
            jobs_dict['testcase_failure'] = tests_faild
            print(jobs_dict)
            jobs_list.append(jobs_dict)
        return jobs_list
  1. 开发DJango接口,可参考 https://blog.csdn.net/m0_48468018/article/details/129640549

3.1 开发数据模型

class JenkinsJobModel(models.Model):
    objects = models.Manager()
    build_job = models.CharField('任务名称', max_length=255)
    build_number = models.IntegerField('构建编号', default=0)
    build_time = models.DateTimeField('构建时间')
    build_url = models.URLField('构建URL', max_length=500)
    build_result = models.CharField('构建结果', max_length=50)
    testcase_total = models.IntegerField('用例总数', default=0)
    testcase_skips = models.IntegerField('用例跳过数', default=0)
    testcase_failure = models.IntegerField('用例失败数', default=0)
    created_at = models.DateTimeField('创建时间', default=datetime.datetime.now)
    updated = models.DateTimeField('更新时间', auto_now=True)

    def __str__(self):
        return f'{self.build_job}-{self.build_number}'

3.2 同步数据库,python manage.py makemigrationspython manage.py migrate
在这里插入图片描述

3.3 编写serializers代码

class JenkinsJobModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = JenkinsJobModel
        exclude = [
            'created_at'
        ]

3.4 编写视图代码

client = JenkinsClient()

@api_view(['GET'])
def get_all_jobs(request):
    '''
    获取所有任务,首次手工将JENKINS同步到测试管理平台
    '''
    search = request.GET.get('title')
    querysets = JenkinsJobModel.objects.all()
    if not querysets:
        print("表中无记录,则重新调用Jenkins API同步到Django")
        jobs = client.get_all_jobs_info()
        for job in jobs:
            JenkinsJobModel.objects.get_or_create(**job)
        else:
            print(f"总共同步创建{JenkinsJobModel.objects.count()}条JOB记录!")
            querysets = JenkinsJobModel.objects.all()
    elif search:
        querysets = JenkinsJobModel.objects.filter(Q(build_job__icontains=search))
        print(f"按条件搜索匹配{querysets.count()}条记录!")
    else:
        querysets = JenkinsJobModel.objects.all()
    serializer = JenkinsJobModelSerializer(querysets, many=True)
    return Response(serializer.data, status=status.HTTP_200_OK)

3.5 编写路由并启动服务,测试后端服务是否符合预期
在这里插入图片描述

从vue-element-admin中找到合适的前端代码,定制修改并与后端代码联调

  1. npm run dev 启动vue-element-admin服务,并浏览页面找到合适自己使用的页面,如下是我想要的页面,对模块不熟悉可以借助官方文档https://panjiachen.github.io/vue-element-admin-site/zh/guide
    在这里插入图片描述
  2. 浏览代码的路由,并逐步定位到所属的模块,如table先从router中找到tableRouter,然后定位到@/views/table/complex-table
    在这里插入图片描述
  3. 复制模块的代码和相关联的其他组件的代码到自己的项目中
  4. 根据自己的需求更改代码,如下是我对table部分的代码修改,修改比较简单,主要根据自己写好API返回的值,进行集成
   <el-table
      :key="tableKey"
      v-loading="listLoading"
      :data="joblist"
      border
      fit
      highlight-current-row
      style="width: 100%;"
      @sort-change="sortChange"
    >

      <el-table-column label="序号" prop="id" sortable="custom" align="center" width="50" :class-name="getSortClass('id')">
        <template slot-scope="scope">
          <span>{{ scope.row.id }}</span>
        </template>
      </el-table-column>

      <el-table-column label="任务名称" align="center">
        <template slot-scope="scope">
          <span class="link-type" @click="handleUpdate(scope.row)">{{ scope.row.build_job }}</span>
        </template>
      </el-table-column>

      <el-table-column label="构建编号" align="center" width="100">
        <template slot-scope="scope">
          <span>{{ scope.row.build_number }}</span>
        </template>
      </el-table-column>
      <el-table-column label="构建时间" width="170px" align="center">
        <template slot-scope="scope">
          <span>{{ scope.row.build_time}}</span>
        </template>
      </el-table-column>

      <el-table-column label="构建结果" width="110px" align="center">
        <template slot-scope="scope">
          <span>{{ scope.row.build_result }}</span>
        </template>
      </el-table-column>

      <el-table-column label="用例总数" width="110px" align="center">
        <template slot-scope="scope">
          <span v-if="scope.row.testcase_total>0" style="color:red;">{{ scope.row.testcase_total }}</span>
          <span v-else>{{ scope.row.testcase_total }}</span>
        </template>
      </el-table-column>

      <el-table-column label="用例跳过数" width="110px" align="center">
        <template slot-scope="scope">
          <span v-if="scope.row.testcase_skips>0" style="color:red;">{{ scope.row.testcase_skips }}</span>
          <span v-else>{{ scope.row.testcase_skips }}</span>
        </template>
      </el-table-column>

      <el-table-column label="用例失败数" width="110px" align="center">
        <template slot-scope="scope">
          <span v-if="scope.row.testcase_failure>0" style="color:red;">{{ scope.row.testcase_failure }}</span>
          <span v-else>{{ scope.row.testcase_failure  }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" min-width="100" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button type="success" size="mini">
            <a :href="scope.row.build_url" target="_blank" style="text-decoration: none">
              跳转
            </a>
          </el-button>
          <el-button type="primary" size="mini" @click="handleBuild(scope.row.build_job)">
            构建
          </el-button>
          <el-button type="info" size="mini" @click="handleUpdate(scope.row)">
            编辑
          </el-button>
          <el-button type="danger" size="mini" @click="handleUpdate(scope.row)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  1. 启动Vue和Django服务,vue调用django提供的接口,前后端调试,保证符合自己的需求没有问题产生,调试过程中注意使用console.log()协助定位问题,查看浏览器的Console面板查看问题,可以调整前端和后端保证调通。
    在这里插入图片描述
  2. npm run build 到最后部署的时候,可以使用nginx整合前后端,监听前端接口转发给后端服务,也可以将dist的目录直接配置到django的静态文件夹下,注意在setting文件中指定静态文件的路径,在路由中可以 path('', TemplateView.as_view(template_name="index.html"))直接将vue的index也页面作为主页面和配置re_path(r'^static/(?P<path>.*)$', static.serve, {'document_root': settings.STATIC_ROOT})全局提供静态资源服务
urlpatterns = [
    path('admin/', admin.site.urls),
    path('autotest/', include("autotest.urls")),
    path('', TemplateView.as_view(template_name="index.html")),  ## 这里将url的根路径指向vue中的index页面
    path('api-auth/', include('rest_framework.urls')),
    re_path(r'^static/(?P<path>.*)$', static.serve,
             {'document_root': settings.STATIC_ROOT}, name='static'),
]

增加异步和定时任务

为什么使用异步

以购买机票为例,通常来说,当我们购票时,机票系统需要与航空公司的服务器进行交互,查询座位信息、价格等,因为交互过程可能比较耗时,因此一般是通过异步方式来实现。

具体来说,在购买机票时,我们通常会提交一张订单,然后等待系统返回确认信息。在这个过程中,我们可能会看到一个“正在处理中”的提示,这实际上是机票系统在与航空公司的服务器交互、获得确认信息的时候所调用的异步接口。

异步接口工作的原理是在发起请求后并不立即返回结果,而是在后台继续执行其他任务(如查询其他座位信息),然后再把结果返回,这样就能避免阻塞主线程。

因此,异步的实现能够提高机票系统的处理能力和效率,并且增加用户体验,使用户可以更快速地购买机票。

Celery

什么是Celery

Celery是一个Python开发的分布式任务队列,它可以处理大量任务并且具有较高的可靠性。它本质上是一个任务调度器,将任务发送到工作队列中,由一组工人异步地处理这些任务。最常见的使用方法是将它与Django、Flask、Bottle等Web框架结合使用,Celery可以实现异步处理任务、延迟任务执行等功能。

Celery的工作原理基于三级模型,即任务发布者、消息中间件和任务执行者。在这个模型中,任务发布者将任务传递给消息中间件(如RabbitMQ,Redis等),然后任务执行者从中间件中获取到消息,并执行其中的任务。

Celery具有许多应用场景,如:

  1. 异步处理业务逻辑

  2. 延迟执行一些任务,比如延迟消息推送

  3. 后台定时任务,如定时清理日志

  4. 异步执行复杂的计算任务

  5. 分布式爬虫,多个爬虫进行协同工作,一个负责解析url,另外一个负责提取数据信息
    在这里插入图片描述

Celery的框架组成及原理

Celery是一个开源的分布式任务队列,其由以下组件构成:

  1. Broker: Broker是Celery中最重要的组件,它负责任务的调度和分发。Celery支持多种Broker如:Redis、Rabbitmq、Amazon SQS等。
  2. Worker: Worker是处理任务的工作进程,它从Broker中获取待执行的任务,然后将结果返回给Broker。
  3. Task: Task是为异步执行的函数提供装饰器的实例。当Task被调用时,它将被发送到Broker以便分配给Worker执行。
  4. Producer: Producer是负责生成Task对象并将它发布到Broker的组件。
  5. Beat: Beat是Celery自带的调度器组件,其功能类似于Crontab。可以用来调度定时任务,Producer和Beat配合使用分发给Broker。

Celery的原理如下:

  1. 应用程序将待处理的任务发送到消息代理(Broker)中。
  2. Celery Worker从消息代理中获取任务,并将其分配给Worker进程。
  3. Worker进程执行任务,结果发送回Broker以供查询。
  4. 应用程序从消息代理中获取结果。

这个过程中,消息代理充当了任务分配器和数据传输媒介的角色。 任务可以是任何Python可调用函数或类方法,并且可以在任何数量的节点上并行运行以实现扩展性。
在这里插入图片描述

Celery环境搭建

  1. celery安装
pip install celery
pip install eventlet (windows必装)
  1. regis安装 pip install redis
  2. celery监控flower pip install flower

Celery windows环境为什么用到eventlet?
在 Windows 环境下,Celery 默认使用了 eventlet 作为任务执行的协程库,是因为 Windows 平台下没有像 Linux 平台上的 gevent 这样的高效协程库。
Eventlet 是一种 Python 协程库,它提供了简单易用的 API,使得编写异步代码变得简单。Celery 使用 eventlet 作为后台执行器来利用 Windows 上的并发优势,可以提高同步函数和方法的执行速度,从而避免阻塞现象产生,提高 Celery 的任务执行效率。

在Python代码中使用Celery

以下是使用Celery+Redis的Python代码中实例化Celery对象的示例:

  1. 创建一个celery_task.py文件,并贴入如下代码
from celery import Celery
import time

app = Celery('tasks', broker='redis://127.0.0.1:6379/0',
             backend='redis://127.0.0.1:6379/1')


@app.task
def send_email(name):
    print("向%s发送邮件..." % name)
    time.sleep(5)
    print("向%s发送邮件完成" % name)
    return "ok"


@app.task
def send_msg(name):
    print("向%s发送短信..." % name)
    time.sleep(5)
    print("向%s发送短信完成" % name)
    return "ok"
  1. 创建一个celery_demo.py文件作为一个测试文件
from celery_task import send_email, send_msg

# celery_task 是创建的异步执行文件

if __name__ == '__main__':
    for i in range(1, 10):
        result1 = send_email.delay("张三")
        print(result1.id)
        result2 = send_email.delay("李四")
        print(result2.id)
        result3 = send_msg.delay("王五")
        print(result3.id)
        result4 = send_msg.delay("赵六")
        print(result4.id)

在这里,我们先使用 Celery() 函数创建一个 app 实例,其中将 Celery 实例命名为 tasks。链接到指定的Redis消息代理和结果存储后端。

在这里使用了 Redis 作为我们的消息代理和结果后端,使用地址 redis://localhost:6379/0,其中 0 表示 redis 中第一个数据库,如果你需要更多数据这点可以根据自己的需求进行设置。之后我们用 @app.task 来定义任务。

然后测试代码中启动队列运行

  1. 最后启动服务

启动celery调度,确保启动的时候可以找到celery_task,可以切换到对应的目录下启动

celery -A celery_task  worker -l info -P eventlet

启动flow服务进行监控,监控的数据库需要和celery_task代码中的保持一致,可以监听到对应的数据

celery --broker=redis://127.0.0.1:6379/0 flower --address=0.0.0.0 --prot=5555

如图是运行test后flower显示
在这里插入图片描述

Django环境中接入celery

  1. 配置Django项目

在Django项目的settings.py文件中添加以下配置,其中myproject为项目名:

CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'  # Redis作为消息中间件
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'  # Redis作为任务结果存储
CELERY_TIMEZONE = "Asia/Shanghai"  # 指定时区,不指定默认为 'UTC'
  1. 创建Celery实例对象

在Django项目的根目录下,创建一个名为celery.py的文件,添加以下代码:

import os
import django
from celery import Celery
from myproject import settings

# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
# 创建Celery实例对象
app = Celery('myproject')
# 指定中间人
app.config_from_object('django.conf:settings', namespace='CELERY')
# 自动注册任务
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
  1. 项目的init文件中加入如下代码:
__all__ = ['app']

在这里插入图片描述

  1. 在app中创建tasks任务

在Django项目的某个app中创建tasks.py文件,一定是该文件,符合celery的编码规范,并编写任务代码:

from celery import shared_task

@shared_task
def add(x, y):
    return x + y
  1. 添加路由和并在views.py中调用celery任务
from django.http import HttpResponse
from .tasks import *
def task_add_view(request):
    add.delay(100, 200)
    return HttpResponse(f'调用函数结果')
  1. 启动Celery服务

使用以下命令来启动Celery服务:

celery -A django项目名 worker -l info -P eventlet

其中celery_client为Celery实例所在的模块,worker表示启动一个工作进程,`-l表示日志等级。

  1. 启动django服务,并进行访问,启动该任务
    在这里插入图片描述

如果调度策略要改成定时任务,则可以在settings指定,添加如下代码

CELERY_BEAT_SCHEDULE = {
    'add-every-30-seconds': {  # 任务名字,随意
        'task': 'api.tasks.add',  # celery任务,这里一定是完整的路径,否则报错
        'schedule': 30.0,  # 定时时间
        'args': (16, 16)  # 需要传递到 task 的参数
    },
}

在这里插入图片描述

并启动beat服务

celery -A 项目名  beat -l info 

beat服务日志
在这里插入图片描述
celery服务日志
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值