快乐学习
前程无忧、中华英才非你莫属!

Pytest全栈自动化测试指南-课程声明!

zhangtongle阅读(455)

尊敬的用户,

近期我们发现有部分用户从非官方渠道购买了盗版课程内容。这不仅损害了我们的合法权益,也影响了您自身的学习体验。

购买正版课程,您将获得:

  • 完整、高清的课程视频
  • 持续更新的学习资料
  • 专业的技术支持与答疑服务
  • 独家的学习社区交流机会

盗版课程不仅违法,且可能存在内容缺失、质量不佳等问题,严重影响您的学习效果。我们呼吁所有用户尊重知识产权,支持正版,共同营造一个健康、有序的学习环境。

Pytest全栈自动化测试指南正版官方发布渠道:

从其它渠道购买的,均属于翻录盗版,严重侵害了原创作者和其他购买课程用户的权益。

为了防止盗版,我们正积极联合平台的法务部门和国家版权局进行维权,追回部分损失,并希望让盗版者受到应有的法律制裁。

为了保护原价购买课程的用户,我们将对课程进行高质量的更新,提供更完善的资料和更优质的服务,彰显课程的真正价值。支持原创,从我们做起,每个订单的支持,都会让作者更有动力去创作更多优质内容。

考虑到部分用户可能经济困难,我们将为特别困难的小伙伴提供5折甚至1折优惠券。

如果您希望获得这些优惠券,我们需要您付出一些简单的劳动,比如在朋友圈多次分享我们的课程。我们将提供宣传软文,帮助您进行简单的广告宣传,时间为期2至3天。通过简单的劳动来获取知识。

1折优惠券仅针对特别困难且对知识有渴望的用户。我们希望您能尊重知识版权,尊重作者的劳动成果,并愿意付出一些劳动来获取知识。

感谢您的理解与支持。

Python3.11下载安装与创建独立虚拟环境

zhangtongle阅读(3024)

一、python 下载安装

1.去https://www.python.org 官网,按照图示点击下载Python3.11.4

2. 双击下载好的安装包,按照图示选自定义安装路径,便于项目管理,并勾选添加环境变量复选框

备注:然后一路next就可以了,

3、快捷键win(窗口键)+ R 打开运行,并键入cmd

备注:ctrl+z 并回车就可以退出解释器。

4. 设置仓库地址
pip config set global.index-url https://mirrors.cloud.tencent.com/pypi/simple


备注: 设置软件模块的仓库地址,让python的模块,从国内豆瓣源镜像仓库下载。这样就不会出现timeout超时异常,模块下载不下来等异常。

注意: 豆瓣镜像源近期失效了,请更换腾讯或者清华的镜像源,请参考文字描述,不要参考图片中。

二、python 设置虚拟环境

1. 安装虚拟环境管理模块

pip install virtualenv
pip install virtualenvwrapper-win

2. 设置虚拟环境的系统环境变量

WORKON_HOME :D:\PyJob\virtualenv

D:\PyJob\virtualenv 这个路径要提前创建好,在PyJob文件夹下创建virtualenv 文件夹,用来存储各种独立的虚拟环境。防止冲突。

在Windows 10中,可以通过以下步骤快速打开系统环境变量:

1. 使用键盘快捷键 Win + X
2. 在弹出的菜单中,选择“系统”。
3. 在系统菜单中,点击“高级系统设置”。
4. 在弹出的对话框中,点击“环境变量”按钮。
5. 这将打开“环境变量”对话框,其中包含系统环境变量和用户环境变量的设置。

通过以上步骤,您可以快速打开系统环境变量并进行相应的设置。

3. 虚拟环境创建和管理

 mkvirtualenv -p D:\PyJob\py311\python.exe chatgpt  # 创建名字叫chatgpt的独立虚拟环境
 workon # 查看所有虚拟环境
 workon chatgpt # 进入和切换到chatgpt环境


备注:这样做的好处是,后期多个项目时,项目与项目之间不冲突,项目依赖的资源相互独立。

指定解释器,则使用
mkvirtualenv --python=python3安装路径 ztloo

包含系统解释器中已经安装的python包
mkvirtualenv test1 --system-site-packages(默认不包含系统环境中的python包)

删除独立虚拟环境
rmvirtualenv test1

如何与ChatGPT交流?ChatCatsy AI工具让你的对话更加智能!

zhangtongle阅读(2553)

📌 免责声明:本软件仅供学习测试使用,请勿使用本软件从事违法活动,否则一经发现,后果自负,将配合相关部门严厉打击。

本AI工具软件是基于ChatGPT技术研发而成,旨在提供更便捷、更智能的聊天体验。但请注意,该软件仅作为一种辅助工具,不能代替人类的判断和决策,也不能保证100%准确性和完整性。因此,使用本聊天软件所产生的任何结果和后果,本人不承担任何法律责任。用户需自行承担使用该软件的全部风险和责任,并且应该在使用前仔细阅读软件说明和功能介绍,了解其局限性和适用范围。最后,我们保留对免责声明的解释权和修改权,并且不对因软件使用导致的任何损失或损害承担法律责任。

第一章:软件介绍

🧑🏼‍🎨
ChatCatsy是一款完全由Python开发的桌面端软件,它可以与ChatGPT进行流畅的交流,并且具有类似Siri的语音交互功能。
只需说出“你好”,就能唤醒它。此外,ChatCatsy还包含了文字转换语音、生成字幕、音频功能以及音频转文字等多种实用功能。

为了满足用户的不同需求,ChatCatsy还提供了详细的设置功能,用户可以控制ChatGPT的版本模型、回答长度、随机性以及问答模式,包括官方API直连、记忆直连和记忆代理等多种模式。
此外,用户还可以对软件的外观进行设置,包括背景图、主题色和软件透明度等。

总之,ChatCatsy是一款功能强大、操作简便、界面美观的AI工具,可以帮助用户更加高效地进行文字和语音交流。如果你需要更多信息或者有任何疑问,请随时联系我们。我们非常期待与您合作,让ChatCatsy成为您的得力助手。

📌 说明:目前软件只支持Windows 版本,因为开发小哥手里暂时没有Mac电脑。当有些开发经费后,很快就能支持Mac 版本,敬请期待。


第二章:软件基本使用

🔑 step1: 获取官方网盘下载链接:

链接:https://pan.baidu.com/s/1Kk94l_X_weoQNli22S_MZg?pwd=abcd
提取码:abcd


🔑 step2: 把软件下载后,放在不含中文的文件夹里面。此软件是免安装的,双击即可使用。

🤖 软件版本区别:

ChatCatsyV1.0 : 内部不包含代理模式,需要自行连通国际互联网,并设为全局模式,才能使用内部功能。

ChatCatsyV1.1:内包含代理模式,不用连通国际互联网,便能使用软件内部问答模式,文字转语音。

注意:ChatCatsyV1.1 在V1.0的基础上,多了代理模式,如果在V1.1 使用内置代理模式,会导致语音转文字功能异常,因代理服务器暂时未支持语音转文字接口。如果想使用音频转文字功能,请联通国际互联网。


🔑 step3: 软件正版激活 打开软件后,如果是第一次使用,会弹窗激活对话框,要求使用者激活。对机器码右键copy 后,发送给开发小哥,小哥把对应的激活码发给你后,就可以的正常使用软件。一机对一码,把激活码保存好哟!


🔑 step4: 电脑网络设置为全局可连通国际互联网模式。(如果使用的ChatCatsyV1.1 版本,可以忽略此步骤。

🔑 step5: 设置API key


🔑 step6:验证软件服务是否正常

ChatCatsyV1.0 版本验证:(需要做step4步骤的操作)

ChatCatsyV1.1 版本验证:

第三章:软件定价

ChatCatsyV1.0 : 30元/个

ChatCatsyV1.1 : 50元/个

独立账号API秘钥 : 20元/个 (纯手工注册,数量有限!不单独供给!)

远程调试服务:20元/次

1级 2级 3级 4级 5级 6级 7级
正版软件 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.1 ChatCatsyV1.1 ChatCatsyV1.1
独立GPT账号
远程调试
价格 30 元 50元 50元 70元 50元 70元 90元

独立GPT账号-API秘钥 ,包含5美元额度,如何验证:

📌 注意1:全新的独立账号,额度剩余是5美元。

📌 注意2不要用共享账号,会面临随时封号和存在访问竞争,同一时间段,别人能用,你就用不了。隐私泄露!即使我们使用独立账号,提问数据也要不要涉及隐私信息,脱敏后进行知识的问答。

📌 注意3:当你的账号或秘钥,稳定使用后的某天,因不可抗力因素或因为多人使用你的账号,被openai官方封号, 损失自行承担。

📌 联系方式:开发小哥WeChat &qq : 1071235258

ChatGPT翩然起舞,以文本为笔创意无限

zhangtongle阅读(2637)

ChatGPT翩然起舞以文本为笔创意无限   原价198  重磅上新价:118.8
https://edu.51cto.com/course/33827.html

第一部分:ChatGPT基础

在这部分中,你将学习ChatGPT的基本概念和原理,了解自然语言处理的基本技术,以及如何使用ChatGPT进行对话和生成文本。

第二部分:ChatGPT prompts 提示词工程

这部分将教你如何构建有效的ChatGPT提示词,通过合理的提问和指导,引导ChatGPT生成你想要的回答和结果。

第三部分:ChatGPT高级应用

这部分将涵盖一系列高级应用,包括使用AI文本到图像生成器创造你想要的图像,语音处理技术,PPT制作工具,思维导图的制作方法以及视频制作的基本原理和工具。

第四部分:ChatGPT 开发框架和实用工具

在这部分中,你将学习ChatGPT的开发框架和常用实用工具,了解如何进行定制化开发和应用,以满足个人或企业的需求。

第五部分:ChatGPT在自动化办公中的应用

这部分将介绍如何将ChatGPT应用于自动化办公场景,例如自动回复邮件、智能日程安排、自动化报告生成等,提高工作效率和减轻重复性任务的负担。

第六部分:ChatGPT在商业应用中的应用

在这部分中,你将了解如何将ChatGPT应用于商业场景,包括市场调研、客户服务、智能推荐等领域,帮助企业提升竞争力和用户体验。

通过学习这门课程,你将掌握ChatGPT的基础知识和应用技巧,了解如何使用AI技术解决实际问题,并在自动化办公和商业应用中获得成长和优势。课程内容以图文结合的形式呈现,帮助你更好地理解和应用所学知识。

Pandas之read_excel函数的重要性

zhangtongle阅读(2712)

1、普通使用


excel_path = r'某公司销售数据-全国订单明细.xls' # Excel 数据路径
sales_data = pd.read_excel(excel_path) # 返回的DataFrame
sales_data.head(1) # 使用head 获取前1个数据

2、读取指定sheet

excel_sheet

pd.read_excel(excel_path,sheet_name='成绩表') # 读取成绩表

pd.read_excel(excel_path,sheet_name=2) # 读取全国订单明细,读取sheet的索引为2的表

3、指定表头

excel_header

把考勤表的第二行当表头

pd.read_excel(excel_path,sheet_name='考勤表',header=1)

4、只读取表中需要的列

# 通过列名
pd.read_excel(excel_path, usecols=['顾客姓名','订单数量','销售额'])[:2]
顾客姓名 订单数量 销售额
0 李鹏晨 6 261.54
1 王勇民 2 6.00
# 通过Excel 列的标识符。
pd.read_excel(excel_path, usecols="A:E")[:2]
订单号 订单日期 顾客姓名 订单等级 订单数量
0 3 2010-10-13 李鹏晨 低级 6
1 6 2012-02-20 王勇民 其它 2

5、将某列(字段)作为查询的的条件和依据)

# 将订单日期作为查询条件
df = pd.read_excel(excel_path,index_col=1,usecols="A:E")[:2]
df.loc['2011-07-15'] # 查询订单日期2011-07-15的所有数据
订单号 顾客姓名 订单等级 订单数量
订单日期
2011-07-15 32 姚文文 高级 26
2011-07-15 32 姚文文 高级 24

6、将多个字段作为查询条件

# 将订单日期和 订单等级作为查询索引(条件)
df = pd.read_excel(excel_path,index_col=[1,3],usecols="A:E")
df = df.sort_index()  # 需要将索引(查询字段)排序,要不不然会报警告

df.loc['2012-11-15','低级'].reset_index() # 查询日期和订单等级
订单日期 订单号 顾客姓名 订单数量
0 2012-11-15 13346 周雨生 44

7、跳过表中最后无用的数据

skip_footer

# 跳过工资表中的最后7行内容,不读取
pd.read_excel(excel_path,sheet_name='工资表',usecols="A:B",skipfooter=7)

8、指定Excel中的数据类型

# Excel 中salary数字列,夹杂了文字。需要转str,进一步的过滤和处理
df = pd.read_excel(excel_path,sheet_name='工资表',usecols="A:B",skipfooter=7, \
              dtype={'name': str, 'salary': str})

Python-导入模块的最佳实践

zhangtongle阅读(2925)

导入模块的“最佳实践”是什么

通常请勿使用 from modulename import * 。因为这会扰乱 importer 的命名空间,且会造成未定义名称更难以被 Linter 检查出来。

请在代码文件的首部就导入模块。这样代码所需的模块就一目了然了,也不用考虑模块名是否在作用域内的问题。每行导入一个模块则增删起来会比较容易,每行导入多个模块则更节省屏幕空间。

按如下顺序导入模块就是一种好做法:

standard library modules -- e.g. sys, os, argparse, re
third-party library modules (anything installed in Python's site-packages directory) -- e.g. dateutil, requests, PIL.Image
locally developed modules

为了避免循环导入引发的问题,有时需要将模块导入语句移入函数或类的内部。Gordon McMillan 的说法如下:

当两个模块都采用 "import " 的导入形式时,循环导入是没有问题的。
但如果第 2 个模块想从第 1 个模块中取出一个名称("from module import name")并且导入处于代码的最顶层,那导入就会失败。原因是第 1 个模块中的名称还不可用,这时第 1 个模块正忙于导入第 2 个模块呢。

如果只是在一个函数中用到第 2 个模块,那这时将导入语句移入该函数内部即可。当调用到导入语句时,第 1 个模块将已经完成初始化,第 2 个模块就可以进行导入了。

如果某些模块是平台相关的,可能还需要把导入语句移出最顶级代码。这种情况下,甚至有可能无法导入文件首部的所有模块。于是在对应的平台相关代码中导入正确的模块,就是一种不错的选择。

只有为了避免循环导入问题,或有必要减少模块初始化时间时,才把导入语句移入类似函数定义内部的局部作用域。如果根据程序的执行方式,许多导入操作不是必需的,那么这种技术尤其有用。如果模块仅在某个函数中用到,可能还要将导入操作移入该函数内部。请注意,因为模块有一次初始化过程,所以第一次加载模块的代价可能会比较高,但多次加载几乎没有什么花费,代价只是进行几次字典检索而已。即使模块名超出了作用域,模块在 sys.modules 中也是可用的只有为了避免循环导入问题,或有必要减少模块初始化时间时,才把导入语句移入类似函数定义内部的局部作用域。如果根据程序的执行方式,许多导入操作不是必需的,那么这种技术尤其有用。如果模块仅在某个函数中用到,可能还要将导入操作移入该函数内部。请注意,因为模块有一次初始化过程,所以第一次加载模块的代价可能会比较高,但多次加载几乎没有什么花费,代价只是进行几次字典检索而已。即使模块名超出了作用域,模块在 sys.modules 中也是可用的。

解决循环import的方法主要有几种:

1.延迟导入(lazy import)

  即把import语句写在方法或函数里面,将它的作用域限制在局部。
  这种方法的缺点就是会有性能问题。

2.将from xxx import yyy改成import xxx;xxx.yyy来访问的形式

3.组织代码

  出现循环import的问题往往意味着代码的布局有问题。
  可以合并或者分离竞争资源。
  合并的话就是都写到一个文件里面去。
  分离的话就是把需要import的资源提取到一个第三方文件去。
  总之就是将循环变成单向。

PyWin32系列文章-在过去8小时内发现的系统事件

zhangtongle阅读(3045)

Python对Eventlog的win32访问

如果您需要扫描许多服务器的事件日志或根据事件日志进行特定筛选,python的win32evtlogwin32evdlogutil库为您提供了一种有效的方法。

最重要的库是win32evtlog。使用它,您可以通过调用连接到服务器的事件日志。

实例
以下是基本调用:

logtype='System'
hand=win32evtlog.OpenEventLog(server,logtype)

这将返回一个句柄,您可以从该句柄进行调用,例如一个可以提供事件总数的句柄,或者另一个可以检查每个事件的详细信息的句柄。logtype变量设置为要查看的日志类型。默认值为:应用程序、安全性和系统。

掌握句柄后,您可以询问诸如记录数量或特定事件记录之类的信息:

total=win32evtlog.GetNumberOfEventLogRecords(hand)
flags = win32evtlog.EVENTLOG_BACKWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ
events=win32evtlog.ReadEventLog(hand,flags,0)

ReadEventLog返回一些事件对象,这些对象可能不是全部。您需要不断地检查循环,直到ReadEventLog不再返回事件。您可能注意到ReadEventLog有一个flags参数。标志(win32evtlog库中通常提供)指定如何读取事件日志。

下面是一个从ReadEventLog返回的事件中获取数据的简单循环:

for ev_obj in events:

    the_time=ev_obj.TimeGenerated.Format() #'12/23/99 15:54:09'

    evt_id=str(winerror.HRESULT_CODE(ev_obj.EventID))

    computer=str(ev_obj.ComputerName)

    cat=ev_obj.EventCategory

    seconds=date2sec(the_time)

    record=ev_obj.RecordNumber

    msg=str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))

    source=str(ev_obj.SourceName)

我们使用库win32evtlogutil获取事件的实际文本正文。要获取事件的易读日期,需要为事件对象的TimeGenerated部分指定“Format”方法。

win32evtlogutil可以方便地为我们提供事件日志消息的实际文本正文。如果您想根据关闭时间进行排序,这里有一个方便的函数,它使用python的time和regexp库将事件日志的时间格式转换为秒:

import re
import sys

import time
import traceback

import win32con
import win32evtlog
import win32evtlogutil
import winerror

def date2sec(evt_date):
    regexp = re.compile('(.*)\\s(.*)')  # store result in site
    reg_result = regexp.search(evt_date)
    time_res = reg_result.group() # 年月日时分秒
    res = time.strptime(time_res) # 由字符串转换成日期类型
    (mon, day, yr) = res.tm_mon,res.tm_mday,res.tm_year
    (hr, min, sec) = res.tm_hour,res.tm_min,res.tm_sec
    tup = yr, mon, day, hr, min, sec, 0, 0, 0
    sec = time.mktime(tup)
    return sec

flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ

# This dict converts the event type into a human readable form
evt_dict = {win32con.EVENTLOG_AUDIT_FAILURE: 'EVENTLOG_AUDIT_FAILURE',
            win32con.EVENTLOG_AUDIT_SUCCESS: 'EVENTLOG_AUDIT_SUCCESS',
            win32con.EVENTLOG_INFORMATION_TYPE: 'EVENTLOG_INFORMATION_TYPE',
            win32con.EVENTLOG_WARNING_TYPE: 'EVENTLOG_WARNING_TYPE',
            win32con.EVENTLOG_ERROR_TYPE: 'EVENTLOG_ERROR_TYPE'}

computer = 'localhost'  # 本地localhost
logtype = 'System'
begin_sec = time.time()
begin_time = time.strftime('%H:%M:%S  ', time.localtime(begin_sec))
# open event log
hand = win32evtlog.OpenEventLog(computer, logtype)
print(logtype, ' events found in the last 8 hours since:', begin_time)

try:
    events = 1
    while events:
        events = win32evtlog.ReadEventLog(hand, flags, 0)
        for ev_obj in events:
            # check if the event is recent enough
            # only want data from last 8hrs
            the_time = ev_obj.TimeGenerated.Format()
            seconds = date2sec(the_time)
            if seconds < begin_sec - 28800: break
            # data is recent enough, so print it out
            computer = str(ev_obj.ComputerName)
            cat = str(ev_obj.EventCategory)
            src = str(ev_obj.SourceName)
            record = str(ev_obj.RecordNumber)
            evt_id = str(winerror.HRESULT_CODE(ev_obj.EventID))
            evt_type = str(evt_dict[ev_obj.EventType])
            msg = str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))
            print(':'.join([the_time, computer, src, cat, record,evt_id, evt_type, msg[0:15]]))

        if seconds < begin_sec - 28800: break

    win32evtlog.CloseEventLog(hand)

except:
    print(traceback.print_exc(sys.exc_info()))
System  events found in the last 8 hours since: 23:19:40  
Fri Dec  2 23:18:03 2022:zhangtl:Microsoft-Windows-DNS-Client:0:186338:1014:EVENTLOG_WARNING_TYPE:在没有配置的 DNS 服务器响
Fri Dec  2 23:16:28 2022:zhangtl:DCOM:0:186337:10016:EVENTLOG_ERROR_TYPE:<The descriptio
Fri Dec  2 23:14:53 2022:zhangtl:Service Control Manager:0:186336:7036:EVENTLOG_INFORMATION_TYPE:Windows Error R
Fri Dec  2 23:12:53 2022:zhangtl:Service Control Manager:0:186335:7036:EVENTLOG_INFORMATION_TYPE:Windows Error R
Fri Dec  2 23:07:13 2022:zhangtl:Service Control Manager:0:186334:7040:EVENTLOG_INFORMATION_TYPE:Background Inte
Fri Dec  2 23:06:28 2022:zhangtl:DCOM:0:186333:10016:EVENTLOG_ERROR_TYPE:<The descriptio

PyWin32系列文章-递归目录删除和特殊文件

zhangtongle阅读(2840)

Python的win32访问文件属性以启用删除

有时您可能需要执行一些操作,例如删除整个目录树。Python有一些很棒的实用程序可以做到这一点,但具有特殊属性的文件通常无法删除。

为了解决这个问题,您需要使用对SetFileAttributes的win32调用作为普通文件。

C++调用如下所示:

BOOL SetFileAttributes(LPCTSTR lpFileName,DWORD dwFileAttributes);

您为它提供了两个参数,即文件名和特定属性,并返回是否成功。

相应的python调用是:int=win32api。SetFileAttributes(路径名,属性)

唯一的问题是你从哪里得到属性。它包含在非常方便的win32con模块中,特别是win32con.FILEATTRIBUTE*。您可以将文件设置为只读、存档、隐藏等。我们关注的是将其设置为正常,因此我们希望:win32con.file_ATTRIBUTE_normal

下面的示例可能很有用,但当然要小心,因为它会删除很多内容。这是一个递归函数。该示例还使用了os模块中的一些方便的函数。

实例

以下是如何删除目录树的基本示例:


import os

import win32api
import win32con

def del_dir(self, path):
    for file in os.listdir(path):
        file_or_dir = os.path.join(path, file)
        if os.path.isdir(file_or_dir) and not os.path.islink(file_or_dir):
            del_dir(file_or_dir)  # it's a directory reucursive call to function again
        else:
            try:
                os.remove(file_or_dir)  # it's a file, delete it
            except:
                # probably failed because it is not a normal file
                win32api.SetFileAttributes(file_or_dir, win32con.FILE_ATTRIBUTE_NORMAL)
                os.remove(file_or_dir)  # it's a file, delete it
        os.rmdir(path)  # delete the directory here

Pytest全栈自动化测试指南-入门

zhangtongle阅读(2753)

Pytest介绍

Pytest是一个成熟的全功能Python测试工具,可以帮助您编写更好的程序。该pytest框架使编写可读测试变得容易,并且可以扩展以支持应用程序和库的复杂功能测试。pytest需要:Python 3.7+ 或 PyPy3。

Pytest特点

开箱即用.自动发现测试用例简化断言语句,统一为assert丰富的插件架构,超过 800 多个外部插件具有灵活的扩展性和方便的参数化方法

安装&使用

$ pip install  pytest
$ pytest --version
pytest 7.1.2

命名规则&断言

  1. 模块:test_.py 或_test.py。
  2. 函数:test*。
  3. 类:Test*,测试类不能有init函数。
  4. 断言:assert ,支持所有python的布尔表达式

用例执行顺序

  1. 在包含用例的项目根路径下(root-dir)执行:pytest -v
  2. 目录和py文件:按照ascii码排序方式,进行文件递归顺序收集和运行
  3. py文件中:按照代码从上到下
  4. 验证执行顺序:pytest --collect-only

命令行选项

pytest自动化测试

assert 布尔表达式

  • [x] 比较运算符:【>】【<】【<=】【>=】【==】【!=】
    例如:assert actual == expected

  • [x] 身份和成员运算符: 【is】、【is not】、【in】、【not in】
    例如: assert expected in actual

  • [x] 逻辑运算符和布尔函数:【not】【and】【or】【startswith()】
    例如 :assert not expected
    例如 :assert version.startswith("3.8")

待测student功能

# ---------------------------------student.py--------------------------------------
# 以字典的形式返回学生的姓名和成绩
def student_score():
    return {'小明': 99, '小红': 100}

# 以列表的形式返回学生的姓名
def student_name():
    return ['小明', '小红']

编写pass 与fail 用例

# ---------------------------------test_01_pass_fail.py---------------------------
# 这是通过用例
def test_pass():
    # 期望值
    expected = 1
    # 实际值
    actual = 1
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是失败,不通过用例
def test_fail():
    # 期望值
    expected = 2
    # 实际值
    actual = 3
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# ---------------------------------test_02_datatype.py----------------------------
from btest.Day1.student import student_score, student_name

# 这是student_score的验证全数据等式用例
def test_student_score():
    # 期望值
    expected = {'小红': 100, '小明': 99}
    # 实际值
    actual = student_score()
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是student_score 的验证部分数据等式用例
# 验证小红是否等于100,是:pass 、否:fail
def test_student_score_other():
    # 期望值
    expected = 100
    # 实际值
    actual = student_score()['小红']
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是student_name 的包含用例:
# 验证小明是否在学生姓名列表中,是:pass(通过), 否:fail(失败)
def test_student_name():
    # 期望值
    expected = '小明123123'
    # 实际值
    actual = student_name()
    # 通过判断(预期数据)是否在实际数据中,在:pass,不在:fail
    assert len(actual) == 2
    assert expected in actual

多断言

# ---------------------------------test_03_many_assert.py-------------------------
# 安装: pip install pytest-assume -i https://pypi.douban.com/simple
from pytest_assume.plugin import assume

from btest.Day1.student import student_score

def test_student_score_hard():
    actual = student_score()

    with assume: # 实际数据类型是否跟预期数据类型一致。
        assert isinstance(actual, dict)

    with assume: # 实际的数据长度是否跟预期长度相同
        assert len(actual) == 3

    with assume: # 预期数据是否在实际数据内
        assert '小红123123' in actual

    with assume: # 实际数据是否等于预期数据
        assert actual['小红'] == 60

自定义异常信息

# ---------------------------------test_04_custom_fail.py-------------------------
import pytest
from pytest_assume.plugin import assume

from btest.Day1.student import student_name

def test_student_name_hard_custom_fail():
    actual = student_name()
    with assume:  # 实际的数据长度是否跟预期长度相同
        assert len(actual) == 3, \
            f"实际数据长度:{len(actual)} 与预期数据长度:{3}不相同!!"

    with assume:  # 预期数据是否在实际数据内
        assert '小红' in actual, \
            f"预期数据:{'小红'}没在实际数据中:{actual}!!"

    if '小乐' not in actual:
        pytest.fail(f"预期数据:小乐,没有在实际数据{actual}中")

处理异常

# ---------------------------------test_05_exceptions.py--------------------------
import pytest

from btest.Day1.student import student_score

# 通用try/finally 处理用例异常
def test_student_score_error():
    actual = student_score()
    try:
        actual['小红'] = actual['小红'] + '10'
    except:
        pass
    finally:
        assert '小乐' in actual, "小乐没有在学生成绩表里!!"

# pytest用例异常处理
def test_student_score_raise():
    actual = student_score()
    with pytest.raises(Exception):  # 更具可读性且不易出错。
        actual['小红'] = actual['小红'] + '10'
        # assert '小乐' in actual # 不会执行
    # 会执行
    assert '小乐' in actual, \
        f" 预期数据:小乐,没有在实际数据中{actual}!!"

# ---------------------------------test_06_get_error.py---------------------------
"""
1、获取用例的所在的模块、
2、获取用例的名称、
3、获取用例的具体错误信息。
"""

import inspect  # 从实时 Python 对象中获取有用的信息

import pytest

# python-inspect 捕获详细异常信息
def test_inspect_info():
    # 期望值为 模块名::用例名::错误信息
    expected = 'test_06_get_error::test_inspect_info::division by zero'

    with pytest.raises(Exception) as exc_info:
        c = 2 / 0

    # 获取错误文本:exc_info.value.args[0]
    # 如获取错误类型:exc_info.type
    error_info = exc_info.value.args[0]  # 获取用例具体错误信息

    module_name = inspect.getmodulename(__file__)  # 获取用例所在模块
    method_name = inspect.stack()[0][3]  # [0][3]获取用例名字,[1][4][0]获取用例名字和参数

    actual = f"{module_name}::{method_name}::{error_info}"
    assert actual == expected

# Pytest内置功能捕获异常信息
def test_get_raises(request):
    # 期望值为 模块名::用例名::错误信息
    expected = 'test_06_get_error::test_get_raises::division by zero'

    with pytest.raises(Exception) as exc_info:
        c = 2 / 0

    error_info = exc_info.value.args[0]

    module_name = request.module.__name__.split('.')[-1]  # 获取模块 包名.test_06xxx
    method_name = request.function.__name__  # 获取用例名字
    actual = f"{module_name}::{method_name}::{error_info}"
    assert actual == expected

数据类

Dataclass这个模块提供了一个类装饰器和一些函数,用于自动添加生成的 special method,例如 init() 和 repr() 到用户定义的类。 它最初描述于 PEP 557 .

对标准库的补充,称为数据类。可以将数据类视为“具有默认值的可变命名元组”

数据类使用普通的类定义语法,你可以自由地使用继承、元类、文档字符串、用户定义的方法、类工厂和其他 Python 类特性.

装饰器: https://www.ztloo.com/2021/11/06/decorators/

Python术语对照社区文档: https://docs.python.org/zh-cn/3/glossary.html?highlight=decorator

special method(特殊方法) :https://docs.python.org/zh-cn/3/glossary.html#term-special-method

PEP 557(Python 增强建议) :https://www.python.org/dev/peps/pep-0557

标准库:https://docs.python.org/zh-cn/3/library/index.html

命名元组: https://docs.python.org/zh-cn/3/library/collections.html?highlight=namedtuple

# ---------------------------------face_to_object.py------------------------------
from dataclasses import asdict, dataclass, astuple, replace

# https://docs.python.org/3/library/dataclasses.html?highlight=dataclass#module-dataclasses

@dataclass
class GirlFriend:
    # 节省了__init__函数
    name: str
    age: int
    height: int = 170  # cm
    weight: int = 50  # kg

    @classmethod
    def from_dict(cls, d):
        return GirlFriend(**d)

    def to_dict(self):
        return asdict(self)

    def to_tuple(self):
        return astuple(self)

    def update(self, **changes):
        return replace(self, **changes)

if __name__ == '__main__':
    # 把字典转行成类对象
    ym_dict = {'name': '杨幂', 'age': 18, 'height': 170, 'weight': 68}
    ym = GirlFriend.from_dict(ym_dict)
    print('我是类对象型杨幂', ym)

    # 把类对象转化成字典
    ym_dict = ym.to_dict()
    print('我是字典型杨幂:', ym_dict)

    # 把类对象转化成元组
    ym_tuple = ym.to_tuple()
    print(f'我是元组型杨幂:{ym_tuple}')

    # 把杨幂修改成刘亦菲
    lyf = ym.update(name='刘亦菲', age=22)
    print(f'我是刘亦菲:{lyf}')

自定义辅助断言函数

import pytest

from btest.Day2.face_to_object import GirlFriend

def assert_identical(gf_1, gf_2):
    if gf_1.name != gf_2.name:
        pytest.fail(f"name不匹配. {gf_1.name} != {gf_2.name}")

def test_identical():
    gf_1 = GirlFriend("刘亦菲", 18, 170, 60)
    gf_2 = GirlFriend("刘亦菲", 18, 170, 60)
    assert_identical(gf_1, gf_2)

更多案例,更多内容,请点击: http://weike.fm/KzXbA994f

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715
error: Sorry,暂时内容不可复制!