自动化测试高级应用
一、HTML测试报告
对软件测试人员来讲,需要一份漂亮且通俗易懂的测试报告来展示自动化测试成果。显然,一个简单的Log文件是不够的。
HTMLTestRunner 是Python 标准库 unittest 单元测试框架的一个扩展,它生成易于使用的 HTML 测试报告。HTMLTestRunner 是在BSD 许可证下发布的。
下载地址如下:
这个扩展非常简单,只有一个HTMLTestRunner.py 文件,选中后单击鼠标右键,在弹出的快捷菜单中选择目标另存为,将它保存到本地。安装方法也很简单,将其复制到Python安装目录下即可。
Windows:将下载的文件保存到 ...\Python3x\Lib目录下。
Linux:以Ubuntu为例,首先需要打开终端,找到Python的安装目录。打开终端后,输入Python命令进入Python交互模式,通过sys.path 可以查看本机的Python的安装目录。
0|11.1 修改 HTMLTestRunner
因为 HTMLTestRunner.py 是基于 Python2 开发的,为了使其支持 Python3 的环境,需要对其中的部分内容进行修改。
0|21.2 生成 HTML 测试报告
以 test_baidu.py 文件为例生成 HTMLTestRunner 测试报告。
代码分析
- 首先,将 HTMLTestRunner 模块用 import 导入进来。
- 其次,通过 open() 方法以二进制写模式打开当前目录下的 result.html,如果没有,则自动创建该文件。
- 接着,调用 HTMLTestRunner 模块下的 HTMLTestRunner 类。stream 指定测试报告文件,title 用于定义测试报告的标题,description 用于定义测试报告的副标题。
- 最后,通过 HTMLTestRunner 的 run() 方法来运行测试套件中所组装的测试用例。最后通过 close() 关闭测试报告文件。
生成的文档如下图:
0|31.3 更易读的测试报告
现在生成的测试报告还不易读,因为它只罗列了一堆测试类和测试方法,我们需要用心地为测试类和测试方法命名才能提供测试报告的可读性。如果随意命名为 “ test_case1 ”、“ test_case2 ” 等,那么这份报告就失去了可读性,也许时间久了连脚本开发者都不清楚 “ test_case1 ” 是测试什么功能了。
在编写功能测试用例时,每条测试用例都有标题,那么我们能不能也为自动化测试用例加上标题呢?在此之前我们先来学习另外一个知识点:Python的注释。Python的注释有两种,一种叫comment,另一种叫doc string,前者为普通注释,后者用于函数、类和方法的描述。
在类或方法的下方,通过三引号(""" """ 或 ''' ''')来添加 doc string 类型的注释,这类注释在平时调用的时候不显示,可以通过 help() 方法来查看类或方法的这种注释。
回到问题的原点,HTMLTestRunner 可以读取doc string 类型的注释。所以,我们只需给测试类或方法添加这种类型的注释即可。
再次运行测试用例,查看测试报告。如下图:
0|41.4 测试报告文件名
在每次运行测试之前,都要手动修改报告的名称,如果忘记修改,就会把之前的报告覆盖,这样做显然很麻烦,那么有没有办法使每次生成的报告名称都不重复并且有意义?最好的办法是在报告名称中加入当前时间,这样生成的报告既不会重叠,又能更清晰地知道报告的生成时间。
系列结果如下:
0|51.5 项目集成测试报告
目前 HTMLTestRunner 只是针对单个测试文件生成测试报告,我们的最终目的是希望将它集成到 runtest.py 文件中,使其作用于整个测试项目。下面打开 runtest.py 文件进行修改。
1|0二、自动发邮件功能
自动发邮件功能也是自动化测试项目的重要需求之一。例如,我们想在自动化脚本运行完成之后,邮箱就可以收到最新的测试报告结果。假设生成的测试报告与多人相关,每个人都去测试服务器查看就会比较麻烦,如果把这种主动的且不及时的查看变成被动且及时的查收,就方便多了。
SMTP (Simple Mail Transfer Protocol) 是简单邮件传输协议,它是一组用于由原地址到目的地址传送邮件的规则,由它来控制信件的中转方式。
Python 的 smtplib 模块提供了一种很方便的途径用来发送电子邮件。它对 SMTP 协议进行了简单的封装。我们可以使用 SMTP 对象的 sendmail 方法发送邮件,通过 help() 查看 SMTP 所提供的方法如下。
导入 SMTP 对象,通过 help() 查看对象的注释,从中找到 sendmail() 方法的使用说明。
通过 Python 的 SMTP 对象发邮件需要填写邮箱服务器。
1|12.1 发送HTML格式的邮件
本例中,除SMTP模块外,我们还用到了 email 模块,它主要用来定义邮件的标题和正文;Header() 方法用来定义邮件标题;MIMEText() 用于定义邮件正文,参数为 html 格式的文本。登录 receive@123.com 邮箱,查看邮件内容如图:
1|2 2.2 发送带附件的邮件
相比于上一个实例,通过MIMEMultipart() 模块构造的带附件的邮件如下图所示:
1|32.3 查找最新的测试报告
现在已经知道如何通过 Python 编写发邮件程序,但要想和自动化测试项目结合还需要解决一个问题,因为测试报告的名称是根据当前时间生成的,所以如何找到最新生成的测试报告是实现发邮件功能的关键。
首先定义测试报告的目录 result_dir,os.listdir() 可以获取目录下的所有文件及文件夹。利用sort() 方法对目录下的文件及文件夹按时间重新排序。list[-1] 取到的就是最新生成的文件或文件夹。程序运行结果如下
1|42.4 整合自动发邮件功能
解决了前面的问题后,现在就可以将自动发邮件功能集成到自动化测试项目中了。下面打开runtest.py 文件重新进行编辑。
整个程序的执行过程可以分为三个步骤:
- 通过unittest框架的 discover() 找到匹配测试用例,由 HTMLTestRunner 的 run() 方法执行测试用例并生成最新的测试报告。
- 调用 new_report() 函数找到测试报告目录 (report) 下最新生成的测试报告,返回测试报告的途径。
- 将得到的最新测试报告的完整路径传给send_mail() 函数,实现发邮件功能。
整个脚本执行完成后,打开接收邮箱,即可看到最新测试执行的测试报告。
# TODO
2|0三、Page Object 设计模式
Page Object 是 Selenium 自动化测试项目开发实践的最佳设计模式之一,它主要体现在对界面交互细节的封装,这样可以使测试案例更关注业务而非界面细节,从而提高测试案例的可读性。
2|13.1 认识Page Object
Page Object 设计模式的优点如下:
- 减少代码的重复
- 提高测试用例的可读性
- 提高测试用例的可维护性,特别是针对 UI 频繁变化的项目
当为 Web 页面编写测试时,需要操作该Web页面上的元素。然后,如果在测试代码中直接操作HTML元素,那么你的代码是极其脆弱的,因为 UI 经常变动。我们可以将一个 page 对象封装成一个 HTML 页面,然后通过提供的应用程序特定的 API 来操作页面元素,而不是在 HTML 中四处搜寻。Page Object 原理如下所示:
page 对象的一个基本经验法则是:凡是人能做的事,page对象通过软件客户端都能够做到。因此,它也应当提供一个易于编程的接口并隐藏窗口中底层的部件。所以访问一个文本框应该通过一个访问方法(accessor method)来实现字符串的获取与返回,复选框应当使用布尔值,按钮应该被表示为行为导向的方法名。page 对象应当将在 GUI 控件上所有查询和操作数据的行为封装为方法。一个好的经验法则是,即使改变具体的控件,page对象的接口也不应当发生变化。
尽管该术语是“页面”对象,但并不意味着需要针对每个页面建立一个这样的对象,例如,页面有重要意义的元素可以独立为一个page对象。经验法则的目的是通过给页面建模,使其对应用程序的使用者变得有意义。
2|23.2 Page Obiect实例
逐段分析,来体会这样设计的好处。
1 创建 page 类
首先创建一个基础类 Page,在初始化方法__intit__() 中定义驱动 (driver)、基本的 URL(base_url) 和超时时间(timeout)等。
定义 open() 方法用于打开 URL 网站,但它本身并未做这件事情,而是交由 _open() 方法来实现。关于 URL 地址的断言部分,则交由 on_page() 方法来实现,而 find_element() 方法用于元素的定位。
2 创建 LoginPage 类
Page 类中定义的这些方法都是页面操作的基本方法。下面根据登录页的特点再创建 LoginPage 类并继承 Page 类,这也是 Page Object 设计模式中最重要的对象层。
LoginPage类中主要度登录页面上的元素进行封装,使其成为更具体的操作方法。例如,用户名、密码和登录按钮都被封装成了方法。
3 创建test_user_login() 函数
test_user_login() 函数将单个的元素操作组成一个完整的动作,而这个动作包含了打开浏览器、输入用户名/密码、点击登录等单步操作。在使用该函数时需要将 driver/username、password等信息作为函数的入参,这样该函数具有很强的可重用性。
4 创建main() 函数
main() 函数更接近于用户的操作行为。对用于来说,要进行邮箱的登录,需要关心的就是通过哪个浏览器打开邮箱网址、登录的用户名和密码是什么,至于输入框、按钮是如何定位的,则不需要关心。
这样分层的好处是,不同的层关心不同的问题。页面对象层只关心元素的定位问题,测试用例只关心测试的数据。
一个有分歧的地方是page对象是否应自身包含断言,或者仅仅提供数据给测试脚本来设置断言。在page对象中包含断言的倡导者认为,这有助于避免在测试脚本中出现重复的断言,可以更容易地提供更好的错误信息,并且提供更接近只做不问风格的API。不在page对象中包含断言的倡导者认为,包含断言会混合访问页面数据和实现断言逻辑的职责,并且导致page对象过于臃肿。
笔者(指虫师)赞成在page对象中不包含断言,虽然我们可以通过为常用的断言提供断言库的方式来消除重复,提供更好的诊断,但从用户的角度去自动化的观点来看,判断是否登录成功是用户需要做得事情,不应该交由页面对象层来完成。
使用Page Object模式之后的另一个好处就是有助于降低冗余。如果需要在10个用例中输入不同的用户名/密码登录,那么用main() 方法写将会变得非常简洁。
因此,Page Object 模型的作用在一个测试人员自己写主场景测试案例时是不容易体会到的,因为你不需要和开发、业务交流案例,也不会写很多重复的动作。但是,当你真正开始尝试ATDD或BDD,当你开始写一些重要的异常分支流程时,当你开始为新需求频繁维护修改案例时,就会意识到Page Object的作用。
最后,Page Object不是万灵药,也不是唯一方案,提高测试案例的可读性,避免案例步骤冗余才是终极目标。
__EOF__

本文链接:https://www.cnblogs.com/dongye95/p/9273089.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!