必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境

文章目录

  • GitHub 分享
  • 项目介绍
  • 工具准备
  • 框架结构搭建
  • case/data/locator/page PO 思想
  • run.py 测试套件
  • common 共用类
  • config.ini 参数化构建项目
  • Assembler 装配器
  • BeautifulReport 报告
  • save_img 截图
  • logging log 日志
  • ParamUnittest 外部传参
  • redis 配置
  • mysql 配置
  • RemoteWebDriver 远程远行
  • 线程存储考虑
  • 报告等文件重名考虑
  • 其他的细节点
  • 思考

GitHub 分享

GitHub 框架源码:python-ui-auto-test

项目介绍

本人使用的是 python + selenium + unittest + PO + BeautifulReport + redis + mysql + ParamUnittest + 多线程 + 截图/日志 + 多浏览器支持 + RemoteWebDriver +文件读取 + 全参数化构建,即在 python + unittest + selenium 基础上加了不少东西。

为什么是 unittest 不是 pytest,因为 pytest 相对 unittest 来讲更容易些,而且二者虽然使用频率都很高,但是 unittest 似乎使用频率要更高一点,并且 unittest 还可做单元测试,于是就选择了 unittest 来搭建。

下面就会进行保姆级搭建讲解O(∩_∩)O

工具准备

  • 建议使用 pycharm

  • 本人 python 3.6 和 pip 工具

  • git 工具,提交代码到远端仓库可用

  • 项目依赖如下:

    BeautifulReport 0.1.2
    ParamUnittest   0.2
    PyMySQL         0.9.3
    futures         3.1.1
    pip             10.0.1	
    redis           3.3.11
    selenium        3.141.0	
    setuptools      39.1.0	
    tomorrow        0.2.4	
    urllib3         1.25.7	
    

采用的是 PageObject 分层结构,什么是 PO 结构可以百度,由于本文内容较多不做赘述。搭建的过程中我使用的是 venv 虚拟环境,大家搭建过程中可用虚拟环境也可用系统环境,虚拟环境和系统环境的区别这里也不做赘述,同时我也把这个 venv 文件夹给 gitignore 了,大家若是从 github 拉下来是看不到这个文件夹的,可以依据此文提供的依赖自行 pycharm 中 install 依赖。

python 语法知识需要补充的同学点击这里

unittest 知识需要充的同学点击这里

git 常用命令可以看这里

github 如何拉取项目看这里

pycharm 以及 idea 中快速编码插件汇总看这里

框架结构搭建

python 项目默认将项目根文件夹作为包,我将其下的 ui-test 作为了包,在 pycharm 的 settings 中搜索 Project Structure,选中 ui-test 点击蓝色的 Sources 然后保存即可,因为防止 python import 时候路径不会出现红色波浪,不过出现了也不会运行出错。采用 PO 思想,大家可以先 install 上面说的依赖,再创建需要的几个文件夹如下图所示:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第1张图片

python-ui-auto-test
    - api-test(api 测试包,未添加内容)
    - ui-test(ui 测试包)
        - base(与项目初始化配置相关)
        - case(测试用例脚本)
        - common(共用方法)
        - data(数据驱动)
        - locator(页面对应的元素定位)
        - page(页面类)
        - report(输出报告)
            - html(html 类型报告)
            - log(log 日志报告)
            - img(测试截图)
        - resource(资源文件夹)
            - config(配置文件)
            - driver(驱动)
        - util(工具类)
        - README.md(项目介绍 md)
        - requirements.txt(项目依赖清单)
        - run_all.py(类似于 testng 文件执行测试套,单线程)
        - run_all_mutithread.py(类似于 testng 文件执行测试套,多线程)
    - venv(虚拟环境的文件夹,github 拉下来后需要自己创虚拟环境)
    - .gitignore(git 忽略文件)
External Libraries
Scratches and Consoles

其中需要着重关注的是 base 文件夹,common 文件夹,case 文件夹,resource 文件夹,util 文件夹和两个 run.py。大致思想是 base 中存放初始化项目的工具,然后 page 中编写页面逻辑代码,page 中可使用 data 的数据和 locator 的元素定位,在 case 中对 page 进行测试组织,通过 resource 中的配置在 run.py 中跑测试用产生的报告放在 report 文件夹中。每个文件夹中含有一个__init__()里头就是对该文件的描述

case/data/locator/page PO 思想

  • case

    我打算测试百度,csdn两个页面的基本流程,我所有的测试模块全部以 test 字段开头,并且所有测试模块中的测试类继承了unittest.TestCase

    在这里插入图片描述

    并且其中的测试方法都以 test 字段打头,通过后面跟上数字来按顺序跑测试方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cy2Cj3d-1575393319808)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1575378041715.png)]

    单个模块去测试的话我们在测试模块下补上这样的代码:

    必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第2张图片

    unittest 的 main 方法执行时会自动去找所有 test 打头的测试方法,测试类中若有 setUp 或者 tearDown 方法,他们会在每个 test 测试方法之前和之后执行,一般存放驱动初始化和驱动退出的操作

  • data

    对应 page 存放指定页面的数据,可以弄成 excel 表格存储指定页面的数据,这里可以直接写成代码,因为考虑到如果项目不稳定,会比较频繁的改动这个地方的数据,用 excel 打开再去改动比较繁琐

  • locator

    与 data 类似,这里存放指定页面的元素定位

  • page

    这里写不同页面的逻辑功能代码,page 需要继承 common 文件夹的 PageCommon 类,同时 PageCommon 再继承 BrowserCommon 类

run.py 测试套件

一个是run_all.py另一个是run_all_mutithread.py分别可以跑单线程和多线程,相当于 testng 的testng.xml只不过这里写的是 python 代码,大致就是用到了 unittest 往测试套中添加测试模块,然后使用了 BeautifulReport 的 report 方法,但实际写的过程中本人把它封装成了 ReportTool 工具类,如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第3张图片

多线程的话使用了 tomorrow 依赖,通过@thread运行测试用例,下面的run_mutithread()方法被 main 调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BQSnJrhK-1575393319811)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1575387128128.png)]

common 共用类

  • PageCommon

    存放页面原生操作的封装,如找元素点击元素等等,对于测试模块有其他较大型的共用方法的封装可以放在其中或者单独弄出一个类,使得所有页面类继承这个新类,然后新类继承 PageCommon,目前是页面类都继承了 PageCommon

  • BrowserCommon

    PageCommon 继承了 BrowserCommon,包含与浏览器相关的共用方法,如浏览器切换窗口句柄,执行 js,驱动获取和关闭等,其构造器会传入一个驱动,所以每次在测试类中初始化一个页面类必须要往里头传入一个驱动才行

    必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第4张图片

config.ini 参数化构建项目

本人将项目几乎所有可配置的参数保存在 ini 文件中,通过工具类 ConfigReader 来对此文件读取参数使用,config.ini 文件中包含 [project],[driver],[redis],[mysql],[screenshot],[html],[log] 一共 7 项配置,后续可能加上 [oracle],[sqlserver],[mongoDB] 等工具的配置,ini 文件部分内容如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第5张图片

那如何读取呢?通过 util 中的 ConfigReader 的 read 方法来读取

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第6张图片

在其他模块中通过ConfigReader().read("project")["driver"]这样的形式即可获取配置文件中的参数,项目完全可以依靠此配置文件来构建整个项目

Assembler 装配器

注意是装配器而不是装饰器!Assembler 装配器的功能就是让测试用例运行之初进行各项功能的配置初始化,当然参数来源于 config.ini 文件。具体怎么使用呢,可以在测试模块的 setUp 方法中assembler = Assembler()来创建,其可以写一个无参的构造器把初始化驱动,redis,mysql 等放在其中,通过 get 方法来获取这些工具,包括 driver,部分代码如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第7张图片

在 tearDown 方法中把所有工具给释放一下,调用装配器中的disassemble_all()方法即可,具体代码可以参考 github 项目源码

这个 Assembler 装配工具其实很像 java +selenium + testng 框架中测试用例继承的 BaseTest 类,只不过 python 使用 unittest 时候都会直接继承到 unittest,那初始化工作交给谁呢,既然不能初始化测试用例时候装填各项配置,那么不如我们直接写一个类在 setUp 中手动装填各项配置吧,于是 Assembler 装配器应运而生

BeautifulReport 报告

测试报告采用了一个依赖——BeautifulReport,可以产出一个比较好看的报告样式,通过其本身的 report 方法即可运行测试套并且直接产生报告,比我之前搭建的 java + testng 的方便多了。但是考虑到报告会重名问题,需要把 BeautifulReport 封装一层外壳变成 ReportTool 工具类,其中有方法可以判断指定目录是否含有同名文件,有的话可以通过递归来将名字刷新成还未出现的,通过尾部“(数字)”这样的形式进行名字刷新,使用了递归算法,同样适用了递归刷新文件名字的还有截图,这一块将在下面的报告文件重名考虑中详细讲到

重名可以覆盖也可以不覆盖,这取决于 config.ini 文件中允许 html 报告被覆盖的一个参数,同样截图重名也含有此参数

其实 ReportTool 有个很重要的方法没做就是多线程运行的时候,BeautifulReport 产生的测试报告会依据线程分开成几个测试报告,可以二次开发封装下 BeautifulReport 来实现将多线程的测试报告放在一个 HTML 报告中,目前未做此修改

save_img 截图

  • BeautifulReport 的截图

    实现了个 ScreenshotTool 工具类,疯转了一下 WebDriver 已提供的截图接口,同样也有重名判断。然后在测试模块的测试方法上加上如下装饰器:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1vsBh5o-1575393319824)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1575389515937.png)]

    装饰器中的参数是截图名字,一般与方法同名即可,但我加了../这样的路径,是因为 BeautifulReport 太屎了,不仅多线程报告不能组合,要程序员二次开发,而且出错截图时候非要从项目/img/参数这样的路径去找图片附在报告里,因此我不得不这样写使的 BeautifulReport 在我指定的路径找截图。

    测试方法一出问题,装饰器就会起作用,首先会找该测试类中的名字是 save_img 的方法并执行,我们把截图工具的截图方法放进去,执行完后,装饰器会从其后配置的参数中去找图片,并把图片放置于 HTML 测试报告中。save_img 方法如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nNM0LeU-1575393319827)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1575389837605.png)]

  • 强制截图

    在测试方法中直接调用一个 save_img 方法即可

logging log 日志

log 日志工具这块参考了一下网络,部分代码如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第8张图片

​ 和可以被调用的方法:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第9张图片

使用的话在测试类中start_info()log().info()这样的方式即可

log 这块参数化配置项特别多,都存在 config.ini 中,但是三种日志输入格式其实也可以配置进 config.ini 文件中,目前没有做

ParamUnittest 外部传参

说实话 unittest 这个框架蛮屎的,感觉远没有 java 的 testng 功能强大,还好拓展库还比较多。这里使用了 ParamUnittest 依赖才实现了外部传参,这个参数存放在 config.ini 文件通过工具读取之后传递到测试类上方的参数中,如下所示:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第10张图片

图中传了一个语言参数和一个环境参数。这样即使通过 jenkins 参数化构建,jenkins 传参到 config.ini 文件中,再传到测试用例中即可

redis 配置

redis 工具配置连接,这个工具类中含有一个无参构造器,创建时就会产生一个连接池并且从连接池中直接生成一个新的连接:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第11张图片

还有其他方法,可以查看 github 源码,此工具类主要被 Assembler 装配器使用

mysql 配置

mysql 工具类关键源码如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDRovwlX-1575393319832)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1575390559770.png)]

此工具主要被 Assembler 装配器使用

这些参数上方已声明,这里未显示,请参考 github 源码

RemoteWebDriver 远程远行

框架中可以远程运行,目前远程远行只完成了 chrome 远程远行的代码编写,是否需要远程运行取决于 config.ini 的配置参数。关键代码如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第12张图片

驱动初始化的工作在 Assembler 装配器中完成

browserVersion 这一参数未补充,以后可以考虑补充此参数

线程存储考虑

由于考虑到希望一个测试类运行完后直接运行下一个测试类,并且在同一个浏览器中,也就是不关闭浏览器使用的是同一个驱动,于是本人在 Assembler 装配工具初始化的时候把装配器对象和线程通过键值对形式保存到一个工具类的静态字典中,这样在另一个测试类中通过获取字典中线程对应的数据,即可取到驱动。

其实有了 ParamUnittest 这个依赖,也可以考虑把驱动放在参数里头,这样一个类中每个测试方法可以使用一个驱动。

反正这里组织用例的方式想当的灵活

报告等文件重名考虑

报告和截图文件重名采用递归方式判断新名字是啥,同样是否支持重名在 config.ini 中可配置。部分源码如下:

必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第13张图片

其他的细节点

  • run.py中会产生如下如效果

    必看超赞!python + unittest + selenium 测试框架 GitHub 源码分享!从头搭建 WebUI 自动化测试环境_第14张图片

  • 路径这块可以优化,由于 BeautifulReport 工具的弊端,各种东西都是死的,必须进行二次开发才能解决问题

思考

与 java + selenium + testng 比较之后可以发现两点 1.testng 远比 unittest 强大 2.结构上的比较

  1. testng 为什么说比 unittest 强大呢?

    testng 支持多线程,支持外部传参,支持用例 xml 组织,支持按照 method,groups,class,test,suite 来组织,支持多种配置,unittest 都不支持,它只支持 BeforeTest 和 AfterTest 也就是 setUp 和 tearDown,还好它的库蛮多的,这也足以看出 java 相对于 python 社区活跃程度和发展之久带来的好处,不过 python 还是很有潜力的

  2. 结构上的差异

    java + selenium +testng 通过测试类继承 BaseTest,BaseTest 中写有 BeforeTest 等组织时期的配置,把驱动等工具放入不同的时期里,unittest 这套框架,我们测试类继承的是 unittest,而且 setUp 这样的方式是直接放在测试类中的,然后再把类似 BaseTest 的初始化配置(Assembler)放在 setUp 方法中手动初始化,之后跑测试用例和 PO 思想 java 和 python 类似的,只不过 java 更智能通过 xml 文件配置用例,python 的unittest 还需要代码形式配置装填用例

你可能感兴趣的:(Selenium)