接口自动化测试吱~python+pytest(1)

前文啰嗦

接口自动化介入时间确定:
答:越早越好,因为测试左移可以为测试侧腾出更充分的时间执行测试,效率提升的同时,以避免了日后项目更改或者delay而压缩测试的时间,从而忙的焦头烂额,还容易出现各种问题。
编写:只有api定义好了,就可以写代码
调试:模块开发完毕就可以调试,未开发完毕就可以采用mock模拟测试:https://blog.csdn.net/qq_40207262/article/details/129468858?spm=1001.2014.3001.5502
项目业务流程的自动化测试持续集成:pycharm+git+jenkins项目持续集成和自动化框架构建(CentOs7.9)

不再做过多赘述

通过python执行接口自动化总共分为三大步:
第一步:准备框架
第二步:写代码
第三步:优化

正文:

1、框架基础介绍

  • 框架结构:python+excel+pytest+allure

  • 要写python代码需要的基本工具:
    python
    pycharm
    下载地址:

  • 搭建环境:

  • 接口数据来源:
    接口文档
    fiddler自己抓包
    swagger在线接口文档

  • 自动化测试框架选择:
    pytest+allure+jenkins+gitlab+jira
    (pytest框架写代码、allure工具生成报告、jenkins构建持续集成、gitlab仓库服务器类型)
    本文只简单介绍本地代码pytest框架+allure报告部分

  • 创建项目下分类目录 6包4夹总计10个,一个项目基本够用
    common:公共的,baseApi.py
    libs:基本代码库包
    test_case:测试用例包
    configs:代码配置包
    tools:工具库包,用于读取文件信息代码
    util:常规方法包
    datas:测试数据/用例文件夹
    logs:测试日志文件夹
    reports:测试报告文件夹
    docs:项目相关文档文件夹
    在这里插入图片描述
    在这里插入图片描述

  • 测试用例类型
    xmind思维导图形式,常见手工测试比较常用
    excel用例,自动化使用
    yaml用例,自动化使用
    json/word/数据库等
    本文采用excel

  • pytest环境搭建

    • 脚本头模板展示信息
      • 打开pycharm-》文件-》设置-》编辑-》代码样式-》文件和代码模板-》python Script
        录入:
# _*_ coding: UTF-8 _*_
#@File     ${NAME}.py
#@Time     ${DATE}{TIME}
#@Name     xxxxxxxxxx
#@Email    xxxx@163.com
#@Software ${PRODUCT_NAME}

在这里插入图片描述

      • 安装pytest,在pycharm底部的终端输入
pip install pytest
pip install pytest-html

在这里插入图片描述

      • 检查是否安装成功:
pip show pytest

在这里插入图片描述

  • 三方库的安装整个接口自动化框架会用到的三方库:可以提前安装一下通过pip
pip install allure-pytest
pip install PyYMAL
pip install request
pip install xlwt
pip install xlrd
pip install xlutils

大概就这么多,其他临时用到可以临时安装,很方便

2、编写接口代码

列举一个项目实例操作,来自采用常见的项目框架为:基于sping boot +vue.js前端的前后端分离的架构。

1、百听不厌的登录接口编写

1、 首先分析一个登录接口大概的思路步骤: 编写在*libs*基础代码库包中

  • 需要url->发送请求,请求方法,请求体(账户、密码);
  • 返回响应信息(token、status)
    • 新建python文件:命名login.py
      在这里插入图片描述
    • 数据获取:开发的接口文档或者fiddler抓包
      以58同城登录为例抓包
      fiddler抓包验证:
      在这里插入图片描述

2、基本请求接口

    • 正常通过手动加密密码输入的情况下,接口通了
      在这里插入图片描述
      配置HOST:
      configs包下创建一个文件:config.py
      配置内容:
HOST= 'http://192.168.xx.xx:8082'

这样就在登录和其他结果引用from configs.config import HOST就可以啦。
在这里插入图片描述
但是登录密码加密了,这里就引入加密的概念:

- **1、Java常用[加密方式](http://www.jsons.cn/base64/)**
	[Base64](http://www.jsons.cn/base64/)加密算法(编码方式)
	[MD5](https://md5jiami.bmcx.com/)加密(消息摘要算法,验证信息完整性)
	对称加密算法
	非对称加密算法
	数字签名算法
	数字证书
- **2、应用场景**
	- 1、 Base64应用场景:图片转码(应用于邮件,img标签,http加密)
	- 2、 MD5应用场景:密码加密、imei加密、文件校验
   - 3、非对称加密:电商订单付款、银行相关业务

登录密码采用MD5加密:

import hashlib

#MD5加密
def get_md5(psw):
    indata = hashlib.md5()  #实例化对象
    indata.update(psw.encode('utf-8'))      #加密操作
    # 调用hexdigest方法,获取加密结果,hexdigest是一个十六进制的字符串值。
    print(indata.hexdigest())               #默认32位小写加密数据
    print((indata.hexdigest()).lower())     #输出32位小写加密数据
    print((indata.hexdigest()).upper())      #输出32位大写加密数据
    print((indata.hexdigest())[8:-8].lower())    #输出16位小写加密数据
    print((indata.hexdigest())[8:-8].upper())    #输出16位大写加密数据


if __name__ == '__main__':
    get_md5('123456')
  • 登录接口自动化还需要加入MD5加密的代码 上述固定写法

3、MD5加密方法后的登录接口脚本:

在这里插入图片描述
:indata:登录的参数,根据用例详情可知,是json格式的键值对{"username":" xxx","psw":"xxx"},所以关联MD5加密方法处理为: indata[paw]=get_md5(indata['psw])
移到utils公共包后,调用get_md5方法:
在这里插入图片描述

4、返回的token的处理

    • 以便后续模块关联使用
      在这里插入图片描述
      :根据响应结果报文中提取到token值:return resp.json()['data']['token']

5、处理测试用例数据

  • 采用excel测试用例自动化流程:
    • 1、读取excel数据关键列数据(ID/path/body/response列等)
    • 2、把数据关联到代码中
    • 3、实际结果和预期结果对比,结果写入excel测试用例实际列
      在这里插入图片描述
    • 用例表头格式:
      在这里插入图片描述
      读写excel表语法:在tools包下新建.py文件“getExcelData.py”
  • 补充下表基础知识:
    Book(class):由xlrd.open_work(“example.xls”)返回
    Sheet(class) 由Book object相关方法返回
    sheets: sheet列表
    sheet_names: sheet名称列表
    Book.sheet_by_name(sheet_name): 按名称提取sheet
    Book.sheet_by_index(sheetx): 按序号提取sheet
    nrows: 行数
    ncols: 列数
    cell(rowx,colx): 第rows行colx列的单元格(行和列定位)
    cell_type(rowx,colx): 数据类型(行和列定位)
    cell_value(rows,colx): 单元格数值(行和列定位)
    col(colx): 第colx列所有单元格组成的列表
    col_types(colx,start_rowx=0,end_rowx=None): 第colx列指定单元格数值类型组成的列表
    col_values(colx,start_rowx=0,end_rowx=None): 第colx列指定单元格数值组成的列表
    读取表格库有pandas/openpyxl/xlrd
    我们选择xlrd,因为它可以保留表格原始格式,方便处理
    表格处理分两步:读取数据写入数据

import xlrd  # 导入读取excel模块
from xlutils.copy import copy  # 导入copy模块


# 读取excel文档
def get_exceldata(sheetName, caseName):  # 定义sheet名称,用例编号名称
    loginlist = []
    # 用例路径
    excel_dir = '../datas/TestCases_V1.0.xls'
    # 打开excel文档,读取数据保持表格格式:xlrd.open_workbook(path, formatting_info=True)
    Book = xlrd.open_workbook(excel_dir, formatting_info=True)
    # 获取指定sheet页并读取对应sheet表内容
    Sheet = Book.sheet_by_name(sheetName)
    # 遍历读取每个单元格需要的请求参数和预期响应数据,打包放入登录列表备用
    indx = 0
    for i in Sheet.col_values(0):  # 第0列为case编号命名,col_value(0)第0列组成的列表
        if caseName in i:  # caseName在i所在的元素中(模糊匹配用例id编号Login00x)
            reqdata = Sheet.cell_value(indx, 9)  # sheet第9列为请求参数数据
            respdata = Sheet.cell_value(indx, 11)  # sheet11列为预期响应数据
            #将json转为字典格式,因为用例是json格式,需要与登录接口代码保持一致
            reqdata=json.loads(reqdata)				
            respdata=json.loads(respdata)			
            loginlist.append((reqdata, respdata))  # 将传参和响应打包成一个元组放入登录备用列表
        indx += 1  # 遍历一行加1
    # pprint.pprint(loginlist)
    return loginlist	#返回请求传参和响应数据,列表形式


if __name__ == '__main__':
    # pprint.pprint(get_exceldata('登录模块', 'Login'))
    get_exceldata('登录模块', 'Login')

写入执行结果:
要操作excel,仅仅通过xlrd库或者xlwt库无法完成,需要引入xlutils库。为保证源数据,copy一份生成新的文档进行编辑。xlrd/xlwt/xlutils关系
若想用yaml配置文件编写测试用例清查阅:https://blog.csdn.net/qq_40207262/article/details/129673077

6、pytest自动化框架脚本

目的:将登录方法和获取用例数据关联,在test_cases包下新建test_login.py文件

  • pytest用法规范:
    • .py文件必须以test_或者_test结尾
    • 测试类必须也Test开头且不能有ini方法
    • 测试方法必须以test开头
    • 断言使用assert
  • 运行pytest脚本:
    • pytest 用例路径 --html=./report/result.html
    • pytest.main(['当前用例路径', '--html=测试报告/xxx.html'])
  • pytest的setup和teardown的用法规则
    • setup_moudle(class/method/function) 在整个所在该<级别>文件中的所有用例<前>执行一次
    • teardown_moudle(class/method/function) 在整个所在该<级别>文件中的所有用例<之后>执行一次
  • 基础框架范例:
import pytest
def in(xx):
	return x+1
	actualresult=xxxx	#实际测试结果
	expectedresult=xxxx	#期望结果
	assert actualresult==expectedresult	#对比是否一致

if_name_=='__main__':
pytest.main('执行文件名','-s','-q')	#执行文件,-s打印输出信息,-q简介输出
  • 上述执行基本脚本为:
import pytest
from libs.login import Login    #导入登入方法
from getexceldata import get_exceldata  #导入用例方法


class Test_login:
    # 数据驱动: 数据样式: [({},{}),({},{})]通过数据驱动简洁实现数据匹配,indata和respdata就是get_exceldata对应的字典数据,放在方法之上,类之下的位置。
    @pytest.mark.parametrize('indata, respdata', get_exceldata('登录模块', 'Login'))
    def test_login(self, indata, respdata):
        # 实际数据
        act_resp = Login().login(indata, False)

        # 断言结果对比
        assert act_resp['code'] == respdata['code'] #对比的参数选择响应数据中的code,自己根据实际选择即可


if __name__ == '__main__':
    # 执行文件,-s 打印信息,-q简化输出
    pytest.main(['test_login.py', '-s', '-q'])

结果打印:
在这里插入图片描述

关于参数化-数据驱动详细清查阅:https://blog.csdn.net/qq_40207262/article/details/129637669

输出一个美化的界面报告比文本结果更好。接下来我们引入allure工具:

7、allure报告

  • 1、环境搭建
    • 下载allure.zip,解压到本地某个目录,
    • 将解压路径allure 2.23/bin 添加到环境变量path中
    • 然后再pip install allure-pytest
    • 验证cmd ,输入allure展示allure使用方法即可
    • 1.allure官方下载地址:
      https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/
      2.选择下载版本,例如:2.9
      在这里插入图片描述
      3.选择压缩包下载,Windows选择.zip的文件
      在这里插入图片描述
      4.下载解压后进入bin目录,复制目录的路径
      在这里插入图片描述
      5.此电脑-系统属性-环境变量-系统变量:点击Path编辑,将复制的bin目录的路径复制到变量值里面,注意末尾以英文分号隔开,点击确定
      在这里插入图片描述
      7.输入allure --version
      看到版本信息后代表环境变量配置成功了
      在这里插入图片描述
      8. 执行pip install allure-pytest
  • 2、用法
  • 方法1、allure报告在本地生成打开查看,allure的语法
  • 需要在代码顶部导入allure, import allureos模块,import os
if __name__ == '__main__':
    # 执行文件,-s 打印信息,-q简化输出,#'--alluredir', '../reports/tmp'allure报告数据的生成路径
    pytest.main(['test_login.py', '-s', '-q','--alluredir', '../reports/tmp'])  
    #在路径下启动allure,生成报告数据源,放在reports/tmp目录下。生成html报告到reports/html目录下
    os.system('allure generate ../reports/tmp -o ../reports/html --clean')   
字段					含义
allure				调用allure程序
generate			生成报告
./reports/tmp	    报告的xml数据源路径
-o					参数名,后面跟html报告存储路径
./reports/html		参数值,指定html报告存储路径
--clean				清除上一次的记录

在reports/html目录下生成allure报告,然后选择打开用浏览器
在这里插入图片描述
展示样式:
在这里插入图片描述

  • 方法2、启allure serve,自动在网页中打开,省去本地查找再打开

if __name__ == '__main__':
    # 执行文件,-s 打印信息,-p简化输出# '--alluredir', '../reports/tmp'allure报告的生成路径
    pytest.main(['test_login.py', '-s', '--alluredir', '../reports/tmp'])
    #起服务allure serve:自动打开浏览器,设置默认浏览器,需要一个容器。导入os 模块
    os.system('allure serve ../reports/tmp ')

.由于allure报告自动生成为比较原始,我们需要增加我们想要的信息展示以及代码的日志等需要增加,所以需要继续优化代码

4、优化代码

1、环境初始化

.@pytest.fixture()
fixture源码详细解
fixture(scope=‘作用域’,params=None,autouse=False,ids=None,name=None):
scope:fixtrue作用域:
function: 默认范围,每个func只运行一次
class: fixture在每个类中只运行一次
module: fixture在每个模块中只运行一次
session: fixture在整个测试周期只运行一次,作用于包
params:可选参数,它将导致多个参数调用fixture功能和所有测试都使用它
autouse:为True 为所有测试激活fixture func可以看到它,为False需要参考来激活fixture
ids:每个字符串ID的列表,每个字符串对应于params就是测试id的一部分,没有将从params自动生成
name:fixture的名称,默认为装饰函数的名称。
应用:作用在制定运行代码范围的首尾位置。
目的:美化python运行脚本,当执行开始时,先运行初始化语句:”开始运行自动化测试“,当结束后,执行初始化语句:"自动化测试运行结束"之类的提示语,更具人性化。
通过fixture的作用域来限定作用范围来执行fixtrue脚本。
————————————————————————————
用法说明固定写法):
在总test_case包下新建一个文件:必须命名conftest.py,pytest框架规则限定这个命名。
在这里插入图片描述

import pytest
#scope指的是fixture的作用域:session<function<class<mudule<
@pytest.fixture(scope='session',autouse=True)
def start_demo(request):
    print("-----开始运行自动化测试-----")

    #清除数据操作
    def fin():
        print("-----自动化测试运行结束-----")
    request.addfinalizer(fin)

一个登录模块前后各执行fixture脚本语句。使用的fixture作用域是session
在这里插入图片描述
fixture也可以手动调用。其他文章再讲。可关注!!

2、定制化执行

pytest.mark.xxx()标签可查阅:https://blog.csdn.net/qq_40207262/article/details/129633178

目的:pytest 的mark标签化:对于pytest可以在每个模块每个类每一个方法和用例前都加上marker,当我们执行pytest时就可以根据标签指定运行。指定某个模块某个类单独执行,不用所有都要跑一遍。
注意:定制化需要注意接口的隔离,不能产生定制化执行有关联必要关系存在的脚步,隔离时也需要用到初始化
用法: .@pytest.mark.xxxx
在这里插入图片描述

指定了标签后,在执行时就可以指定运行:https://blog.csdn.net/qishuzdh/article/details/126236453可参考连接详细用法

if __name__ == '__main__':
    pytest.main(['test_login.py', '-s','-m','login', '--alluredir', '../reports/tmp'])
    os.system('allure generate ../reports/tmp -o ../reports/html --clean')

在这里插入图片描述

  • 问题:运行脚本出现不识别警告
    .PytestUnknownMarkWarning: Unknown pytest.mark.login
  • 解决:pycharm-》设置-》编辑器-》插件,需要下载这款插件解决
    在这里插入图片描述

如果你的pycharm搜不到到官网下载:https://plugins.jetbrains.com/plugin/6981-ini/versions

  • 1、查看你pycharm版本号:
    在这里插入图片描述
  • 2、搜索对应你pycharm的对应年代对应运行版本下载:
    在这里插入图片描述
  • 3、 手动导入安装你的ini插件
    在这里插入图片描述
  • 4、 安装完毕,在pycharm新建一个文档
    在这里插入图片描述
  • 使用方法
  • 1、配置标签
    自定义的标签会被pytest识别不了,出现警告.PytestUnknownMarkWarning: Unknown pytest.mark.xxxx
[pytest]
addopts=-vsq
testpaths=./test_case
markers =
    login: run the test_login test function for tasks project
    p0: test1
    p1: test2
    p2: test3

标记注册好后,可以通过pytest --markers来查看
在这里插入图片描述
就可以正常通过标签执行指定的接口、类、方法或者某些用例了。

3、allure报告定制化

  • 1、浏览器
    建议使用火狐打开allure报告
  • 2、allure用例描述

使用方法__________参数值___________参数说明
@allure.epic() ---------epic描述----------------敏捷里面的概念,定义史诗,往下是feature
@allure.feature()------模块名称 -------------- 功能点的描述,往下是story
@allure.story()---------用户故事--------------- 用户故事,往下是title
@allure.title()---------- 用例的标题-------------重命名html报告名称
@allure.testcase()----测试用例的链接地址–对应功能测试用例系统里面的case
@allure.issue()--------缺陷-----------------------对应缺陷管理系统里面的链接
@allure.description()-用例描述-----------------测试用例的描述
@allure.step() ---------操作步骤-----------------测试用例的步骤
@allure.severity()-----用例等级-----------------blocker,critical,normal,minor,trivial
@allure.link()-----------链接-----------------------定义一个链接,在测试报告展现
@allure.attachment()-附件-----------------------报告添加附件

标题编辑@allure.epic()、@allure.feature()、@allure.story()、@allure.title().
在这里插入图片描述
报告展示更有层次感:
在这里插入图片描述

超链接编辑:jira平台、用例管理平台建立超链接地址:@allure.testcase()、@allure.issue()
在这里插入图片描述
报告展示:
在这里插入图片描述
用例描述、等级详情信息@allure.description()、@allure.severity()
在这里插入图片描述

在这里插入图片描述
定义测试用例级别@allure.severity()
在这里插入图片描述
环境信息配置
report/tmp文件夹下创建一个文件:environment.properties
配置信息:自己填写相关软件版本信息

Browser=Firfox
Browser.Version=77
Stand=test
Apiurl=127.0.0.1/login
python.Version=3.9.2
allure.version=2.13.3

在这里插入图片描述

4、封装邮件

  • python对SMTP的支持

SMTP(Simple Mail Transfer Protocol)是简单传输协议,它是一组用于用于由源地址到目的地址的邮件传输规则。python中对SMTP进行了简单的封装,可以发送纯文本邮件、HTML邮件以及带附件的邮件。
python对SMTP的支持:
①email模块:负责构建邮件
②smtplib模块:负责发送邮件
③正文:html格式和表格格式
④附件:txt文本/图片

方法:在common包下面创建一个python文件:send_email.py
固定模板,根据需要修改:

# _*_ coding: UTF-8 _*_
# @File     send_email.py
# @Time     2023/3/19{TIME}
# @Name     xxxxxxxx
# @Email    xxxxxx@163.com
# @Software PyCharm
import smtplib  # 导入发送邮件模块
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
import pandas as pd

# -----设置服务器所需信息------
mail_host = 'smtp.163.com'  # 163邮箱服务器地址
port = 25  # 非ssl协议端口号
sender = 'chal780@163.com'  # 发件箱地址
mail_pass = 'XDYKNOZZNELMZFKT'  # 密码(部分邮箱为授权码)
receivers = ['2492381866@qq.com']  # 邮件接受方邮箱地址,注意需要[]包裹,这意味着你可以写多个邮件地址群发[]
cc = ['949872664@qq.com', '1319908974@qq.com']  # 抄送方地址

# -----设置email信息-----
message = MIMEMultipart()  # 添加一个MIMEmultipart类,处理正文及附件
message['Subject'] = '[xxx项目]登录接口[测试报告]'  # 邮件主题
message['From'] = sender  # 发件人
message['To'] = ";".join(receivers)  # 收件人
message['CC'] = ";".join(cc)  # 抄送对象

# -----html邮件模板正文附件地址文件手动上传放好-----
allurefile = '../datas/index.html'
# 推荐使用html格式的正文内容,这样比较灵活,可以附加图片地址,调整格式等
with open(allurefile, 'r', encoding='utf-8') as f:
    content = f.read()
# 设置html格式参数
part1 = MIMEText(content, 'html', 'utf-8')  # 邮件内容设置

# -----添加excel格式正文,附件地址文件手动上传放好-----
pd.set_option('max_colwidth', 10000)  # pandas读取表格时,设置最大的列宽。使得表格内容不换行。
data_gender = pd.read_csv('../datas/testreport.csv', sep='\t', index_col=False, encoding='GBK')
temp = data_gender.to_html(index=False)
html_text_tmp = temp.replace('class', 'cellspacing=\"0\" class')  # 表格类型,0表示为单外框线,默认为双外框线。
html_text = html_text_tmp.replace('<th>', '<th Bgcolor=#92cddc>')  # 设置表头填充颜色
html_text = html_text.replace('text-align: right', 'text-align: center')  # 表格内容居中
part2 = MIMEText(html_text, 'html', 'utf-8')

# -----添加txt文本附件,附件地址文件手动上传放好-----
with open('../datas/abc.txt', 'r', encoding='utf-8')as h:
    content2 = h.read()
part3 = MIMEText('testxxxxxxxxxlogs', 'plain', 'utf-8')  # 设置txt参数
# 附件设置内容类型,方便起见,设置为二进制流
part3['Content-Type'] = 'application/octet-stream'
# 设置附件头,添加文件名
part3['Content-Disposition'] = 'attachment;filename="abc.txt"'

# -----添加照片附件,附件地址文件手动上传放好-----
with open('../datas/test2.jpg', 'rb')as fp:
    picture = MIMEImage(fp.read())
    # 与txt文件设置相似
    picture['Content-Type'] = 'application/octet-stream'
    picture['Content-Disposition'] = 'attachment;filename="test2.png"'

# -----将内容附加到邮件主体中-----
message.attach(part1)   # 将html邮件模板添加到容器中'''
message.attach(part2)  # 将表格添加到容器中'''
message.attach(part3)   # 将txt文档添加到容器中'''
message.attach(picture)  # 将图片添加到容器中'''

# -----登录并发送邮件-----
try:
    smtpObj = smtplib.SMTP()  # 连接到服务器
    smtpObj.connect(mail_host, 25)  # 登录到服务器
    smtpObj.login(sender, mail_pass)  # 发送
    smtpObj.sendmail(sender, receivers + cc, message.as_string())
    # 退出
    smtpObj.quit()
    print('success:邮件发送成功')
except smtplib.SMTPException as e:
    print('error:邮件发送失败', e)  # 打印错误

附件源分别放置在datas文件夹下:
注意excel表格为csv格式:表格另存为:csv格式
在这里插入图片描述
在这里插入图片描述
以上封装邮件提供了两种格式邮件模板

  • 1、excel格式样式
  • 2、html样式
    自由选择配置使用,使用哪一个就留下哪个,其他注销掉即可

html邮件模板网上比较多可以自己自定义html邮件样式:样板:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>邮件模板</title>
	</head>

	<body>
		<div style="background: #F0F2F5; padding: 35px; font-size: 14px;">
			<div style="width: 750px; margin: 0 auto; background: url('https://www.henghost.com/images/hc_email_background.png') no-repeat center; background-size: cover;">
				<div style="padding: 0 15px; padding-bottom: 20px;">
					<div style="height: 80px; display: flex; justify-content: space-between; position: relative;">
						<div>
							<a href="https://www.baidu.com/index.php?tn=monline_3_dg" target="_blank" rel="noopener"><img style="margin-top: 20px; width: 150px; height: 50px;" src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F0220%2F50993e6dj00r7kui1000bc000hs006fg.jpg&thumbnail=650x2147483647&quality=80&type=jpg" height="50" border="0"></a>
						</div>
					</div>
					<div style="background: #fff; padding: 0 15px; padding-bottom: 50px;">
						<div style="padding: 0 9px; display: flex; justify-content: space-between; align-items: center; padding-top: 10px; padding-bottom: 10px; border-bottom: 1px solid #DBDBDB;">
							<div style="display: flex;">
								<a style="color: #333; text-decoration: none;" href="https://www.henghost.com/" target="_blank" rel="noopener"><span class="nav-title" style="margin-right: 50px;">某某科技公司</span></a>
							</div>
							<div style="display: flex;">
							</div>
						</div>
						<div style="color: #41bf71; border: 1px solid #41BF71; background: #E0FFEC; padding: 14px 15px; display: flex; margin-top: 20px; margin-bottom: 30px;"><img style="width: 42px !important; height: 42px !important;" src="https://www.henghost.com/images/hc_console_normal.png" width="42">
								<div style="font-size: 16px; font-weight: bold; margin-bottom: 5px;">
                                    本项目测试已经完成!<br/>
                                    测试通过!
                                </div>
						</div>
						<div>
							<div><span style="font-size: 16px; font-weight: bold; position: relative; top: -4px;">测试版本</span></div>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">1.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">2.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">3.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">4.xxxxx</a><br/>


						</div>
						<div style="margin-top: 30px;">
							<div><span style="font-size: 16px; font-weight: bold; position: relative; top: -4px;">测试项目</span></div>


                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">1.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">2.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">3.xxxxx</a><br/>
								<a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">4.xxxxx</a><br/>
							    <a style="border: 1px solid #DBDBDB; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">5.xxxxx</a><br/>
                                <a style="border: 1px solid #DBDBDB; color: #666666; color: #666666; font-size: 14px; font-weight: normal; text-align: left; padding-left: 14px;">6.xxxxx</a><br/>
                                Buglist:<a style="color: #006eff; text-decoration: none;" href="https://my.henghost.com/example.php?id=105807" target="_blank" rel="noopener">jiratestlink</a>

						</div>
						<div style="margin-top: 30px;">
							<div><span style="font-size: 16px; font-weight: bold; position: relative; top: -4px;">测试结论:</span></div>
							<div style="border: 1px solid #DBDBDB; padding: 10px; padding-bottom: 20px; margin-top: 20px;">
								<div style="line-height: 30px;"> 1、测试通过!! </div>
								<div style="line-height: 30px;"> 2、测试通过!! </div>
								<div style="line-height: 30px;"> 3、测试通过!! </div>
							</div>
						</div>
					</div>
				</div>
			</div>
			<table class="responsive-table" style="text-size-adjust: 100%; margin-top: 18px; border-collapse: collapse !important; width: 100%;" border="0" cellspacing="0" cellpadding="0">
				<tbody>
					<tr>
						<td style="font-size: 12px; -webkit-font-smoothing: subpixel-antialiased; text-size-adjust: 100%;" align="center" valign="top">
						</td>
					</tr>
					<tr style="padding: 0px; margin: 0px; font-size: 0px; line-height: 0;">
						<td style="font-size: 12px; -webkit-font-smoothing: subpixel-antialiased; text-size-adjust: 100%;">&nbsp;</td>
					</tr>
					<tr>
						<td style="font-size: 12px; -webkit-font-smoothing: subpixel-antialiased; text-size-adjust: 100%;" align="center" valign="top">
							<p style="line-height: 20.4px; text-size-adjust: 100%; font-family: 'Microsoft YaHei'!important; padding: 0px !important; margin: 0px !important; color: #7e8890 !important;"><span class="appleLinks">邮件由质量中心测试团队发出!</span></p>
						</td>
					</tr>
				</tbody>
			</table>
		</div>
	</body>

</html>

邮件演示:
在这里插入图片描述
在这里插入图片描述

关联执行脚本触发:

参考来自:https://blog.csdn.net/weixin_55154866/article/details/128098092

5、封装日志

用到的时候就调用,不用的话可以不加
tools文件夹下新建一个python文件,命名logBasic.py,固定模板写法

  • 1、封装日志模块
import logging
import time

'''
1、日志存放路径
2、日志文件名
3、日志内容格式:fomat
                2023_3_18 21:41:30 - logBasic.py [代码错误的行号] 级别:具体信息
                执行时间    文件名 [代码错误的行号] 级别:msg(具体信息)
'''



def logger():
    now_time = time.strftime("%Y_%m_%d %H.%M.%S")  # 按时间生成日志文件
    logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                       datefmt="%Y-%m-%d %H:%M:%S %p",
                       filename=f'../logs/{now_time}.txt',
                       level=logging.DEBUG,
                       filemode='a')
    return logging


if __name__ == '__main__':
    log = logger()
    log.debug('---输出用例执行日志---')
  • 2、调用
    在执行代码文件中导入封装类:
    在这里插入图片描述
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值