Python数据统计之禅道BUG统计且自动发送测试报告

时间:2024-02-22 22:16:54

项目参考文献:https://testerhome.com/topics/6135

 

思路:

  • 1、读取禅道数据库数据及状态,把各维度统计数据通过dic格式返回
  • 2、读取数据通过pyecharts类,生成不同类型的报表HTML放入image_html文件中
  • 3、读取image_html文件中本次生成的HTML并生成图片,放入static文件中
  • 4、把图片写入HTML文件中,因为邮件正文是HTML格式
  • 5、文字及图片HTML文件组合邮件正文,进行发送邮件
  • 6、上述功能对外提供服务接口,接口传参为产品ID及项目ID,调取接口即可自动发送测试报告

 

主要用到pyecharts,os,flask,pymysql,yagmail等模块,目前就是初步的小程序,后续再更新一版有界面,可自行选择产品及项目,查看项目各维度情况报表,另外有些日志和异常处理还没有完善

 

目录结构:

 

 

主要代码:

1、数据库数据读取

import pymysql
from  auto_report.o_util import spread,list_dic
from  auto_report.setting import db


#建立数据库连接及执行
def connect_db(sql):
    conn = pymysql.connect( **db,charset=\'utf8\',
                           autocommit=True)
    cur = conn.cursor()  # 建立游标
    sql = sql
    cur.execute(sql)
    r_result =spread(cur.fetchall())
    cur.close()
    conn.close()
    return r_result


#BUG状态统计SQL封装
def sql_pakeage(productid,projectid):

    bug_sql = "select count(*) from zt_bug where product=\'%d\' and project=\'%d\' and deleted=\'0\'"% (
    productid, projectid)

    resolved_bug_sql = "select count(*) from zt_bug where product = \'%d\' and project=\'%d\' and deleted = \'0\' and `status` = \'resolved\' and resolution <> \'postponed\' " % (
        productid, projectid)

    not_resolved_bug_sql = "select count(*) from zt_bug where product = \'%d\' and project=\'%d\' and deleted = \'0\' and `status` =  \'active\' " % (
        productid, projectid)

    postponed_bug_sql = "select count(*) from zt_bug where product = \'%d\' and project=\'%d\' and deleted = \'0\' and `status` <> \'closed\' and resolution = \'postponed\' " % (
        productid, projectid)

    closed_bug_sql = "select count(*) from zt_bug where product=\'%d\'and project=\'%d\' and deleted = \'0\' and `status` = \'closed\' " % (
        productid, projectid)

    return  bug_sql,resolved_bug_sql,not_resolved_bug_sql,postponed_bug_sql,closed_bug_sql



#总的项目BUG情况统计
def  test_project_bug(productid,projectid):

    #总bug数
    all_bug=connect_db(sql_pakeage(productid,projectid)[0])

    #已解决bug数
    resolved_bug = connect_db(sql_pakeage(productid,projectid)[1])

    # 未解决BUG数(当前显示BUG状态为未解决的。包含当前还没被解决的、之前遗留的未解决、以及reopen的BUG(累计数据))
    not_resolved_bug =  connect_db(sql_pakeage(productid,projectid)[2])

    # 延期BUG数
    postponed_bug= connect_db( sql_pakeage(productid,projectid)[3])

    # 已关闭BUG数
    closed_bug = connect_db(sql_pakeage(productid,projectid)[4])

    statistics_bug = { "总BUG数":all_bug[0],"已解决BUG": resolved_bug[0], "未解决BUG": not_resolved_bug[0], "已关闭BUG": closed_bug[0],
                      "延期解决BUG": postponed_bug[0]}

    return  statistics_bug



#未解决及待验证BUG人均分布
def test_pepole_bug(productid,projectid):

    #未解决BUG分布sql
    not_resolved_sql="select assignedTo,count(*) from zt_bug where product = \'%d\' and project=\'%d\' and deleted = \'0\' and `status` =  \'active\' and assignedTo <> \'closed\'  group by assignedTo"%(productid,projectid)

    # 未解决BUG分布
    not_resolved_bug=connect_db(not_resolved_sql)


    return list_dic(not_resolved_bug)



#未解决BUG严重程度统计
def test_level_bug(productid,projectid):

     level_bug_sql="select severity,count(*) from zt_bug where product =\'%d\' and project=\'%d\' and deleted = \'0\' and `status` =  \'active\' and assignedTo <> \'closed\'  group by severity"%(productid,projectid)

     level_bug=connect_db(level_bug_sql)

     return list_dic(level_bug)


#已解决待验证BUG分布
def test_verify_bug(productid,projectid):

       #已解决待验证BUG分布sql
       not_verify_sql="select assignedTo,count(*) from zt_bug where product = \'%d\' and project=\'%d\' and deleted = \'0\' and `status` =\'resolved\'  and resolution=\'fixed\' group by assignedTo"%(productid,projectid)
       # 已解决待验证BUG分布
       not_verify_bug = connect_db(not_verify_sql)

       return    list_dic(not_verify_bug)



#获取项目名称
def test_projectname(projectid):
    projectname="select `name` from zt_project where id=\'%d\'"%(projectid)
    return connect_db(projectname)[0]



#验证项目名称及产品名称是否存在及是对应关系
def test_product_verify(productid,projectid):
    if productid:
        p_sql = "select project from zt_projectproduct where product=%d" % productid
        projectlist=connect_db(p_sql)

        if projectid & projectid in projectlist:

            return True

        else:
            return False

    else:
        return False

2、生成报表,报表基类较简单就不贴码了

from auto_report.setting import html_path,ip,report_path
import os
from auto_report.o_table import charts
from  auto_report.o_data import test_level_bug,test_project_bug,test_pepole_bug,test_verify_bug

b_img=charts() #声明图表类

class create_report:

    #调取图表方法,生成项目BUG状态统计表生成
    def test_project_bug_html(self,productid,projectid,t_time):
        if test_project_bug(productid,projectid):
            b_img.p_render("项目BUG状态统计情况表", test_project_bug,\'test_project_bug\',productid,projectid,t_time)
        else:
            return False

    # 调取图表方法,生成开发人员待解决BUG统计情况表生成
    def test_pepole_bug_html(self,productid,projectid,t_time):
        if test_pepole_bug(productid,projectid):
            b_img.p_render("项目开发人员待解决BUG统计情况表", test_pepole_bug,\'test_pepole_bug\',productid,projectid,t_time)
        else:
            return False

    # 调取图表方法,生成测试人员待验证BUG统计情况表生成
    def test_verify_bug_html(self,productid,projectid,t_time):
        if test_verify_bug(productid,projectid):
            b_img.line_render("项目测试人员待验证BUG统计情况表", test_verify_bug,\'test_verify_bug\',productid,projectid,t_time)
        else:
            return False

    # 调取图表方法,生成未解决BUG严重程度统计情况表生成
    def test_level_bug_html(self,productid,projectid,t_time):
        if test_level_bug(productid,projectid):
            b_img.pie_render("项目未解决BUG严重程度统计情况表", test_level_bug,\'test_level_bug\',productid,projectid,t_time)
        else:
            return False

    #获取HTML文件中文件,且生成图片
    def html_image(self,html_file_list):

        if html_file_list:
            for filename in html_file_list:
                self.new_filename=filename.replace(\'.html\',\'\')
                b_img.p_image(os.path.join(html_path,filename),self.new_filename)
        else:
            return False

    #获取图片文件中的图片,且生成report文件
    def img_report(self,img_file_list):
        if img_file_list:
            for img in img_file_list:
                self.f=open(report_path,"a+",encoding=\'utf-8\')
                html=\'\'\'<div><img src="%s/static/%s"></div>\'\'\'%(ip,img)
                self.f.write(html)
                self.f.close()
        else:
            return False

3、邮件发送

import yagmail
import traceback
from auto_report.setting import mail_info,to,cc,log
from auto_report.o_data import sql_pakeage,test_projectname,connect_db
from auto_report.o_util import read_file


#发送邮件
def send_mail(productid,projectid):

    bug_sql=sql_pakeage(productid,projectid)

    bug_num=[]

    for sql in bug_sql:
        bug_num.append(int(connect_db(sql)[0]))

    project_name=test_projectname(projectid)

    subject="%s项目测试报告"%project_name

    str=\'\'\'<div style="color:#000; font-size: 14px;font-family: arial;"> <span style="font-family: 微软雅黑, Microsoft YaHei; font-size: 16px;">大家好:</span></div><div style="color:#000; font-size: 14px;font-family: arial;">
    <span style="font-family: 微软雅黑, Microsoft YaHei; font-size: 16px;">
    &nbsp;&nbsp;&nbsp;&nbsp;​&nbsp;&nbsp;&nbsp;&nbsp;​&nbsp;&nbsp;&nbsp;&nbsp;​%s项目,目前存在%s个BUG,已解决状态%s个BUG,未解决状态%s个BUG,延期处理状态%s个BUG,已关闭状态%s个BUG;请对应开发注意查收及修改自己名下的BUG。</span></div><div style="color:#000; 
    font-size: 14px;font-family: arial;"><br></div><div style="color:#000; font-size: 14px;font-family: arial;">
    <span style="font-family: 微软雅黑, Microsoft YaHei; font-size: 16px;">​各维度测试情况统计如下图:</span><div><br></div></div>\'\'\'%(project_name,bug_num[0],bug_num[1],bug_num[2],bug_num[3],bug_num[4])


    file_content=read_file("./report.html")

    content=str+file_content


    try:
        mail = yagmail.SMTP(**mail_info)  # 解包方式传入参数
        mail.send(to=to, cc=cc, subject=subject, contents=content)  # 发送邮件

    except Exception as e:
        log.error("发送邮件出错了,错误信息是:\n%s" % traceback.format_exc())  # 捕获错误信息

    else:
        log.info("发送邮件成功")  # 发送成功日志

4、接口服务文件

from auto_report.o_mail import send_mail
from auto_report.o_report import create_report
from auto_report.setting import html_path,image_path,report_path
import os,time
from auto_report.o_data import test_product_verify
from auto_report.o_util import clear,file_list
import flask
import json

report=create_report()


server=flask.Flask(__name__) #当前Python为一个服务

@server.route("/report") #get请求,且连接带参数
def table_data():

    productid=int(flask.request.args.get("productid")) #获取参数产品ID
    projectid = int(flask.request.args.get("projectid")) #获取参数项目ID

    t_time = str(int(time.time())) #获取当前时间戳,作为本次文件的唯一标识

    #判断产品及项目输入是否正确
    if test_product_verify(productid, projectid):

        report.test_project_bug_html(productid, projectid, t_time) #项目BUG状态统计表生成
        report.test_level_bug_html(productid, projectid,t_time) #项目BUG待解决BUG严重程度统计表生成
        report.test_pepole_bug_html(productid, projectid, t_time) #项目待解决BUG人员分布统计表生成
        report.test_verify_bug_html(productid, projectid, t_time) #项目已解决待验证BUG人员分布统计表成

        #生成的图表HTML转图片
        html_file_list = file_list(html_path,t_time)
        report.html_image(html_file_list)

        #图片组成报告
        img_file_list = file_list(image_path,t_time)
        report.img_report(img_file_list)

        #发送报告
        send_mail(productid,projectid)

        data = {"code": 200, "msg": "发送成功"}

        #清除本次报告report.html页面产生的数据
        clear(report_path)


    else:
        data={"code":-2,"msg":"参数错误"} #接口传参错误

    return  json.dumps(data,ensure_ascii=False) #返回JSON格式

server.run(host="0.0.0.0",port=5000,debug=True) #启动服务命令

运行效果:

 

 

 

 

 备注:忽略内容啊,测试随意写的文字,文字可自行修改,哈哈哈哈