易用性、可维护性是衡量一款自动化工具/框架是否好用的主要标准,那么针对大多数人着手测试自动化时最先接触到的、基于 selenium 的 UI 自动化框架,怎样才能做到这几点呢?下面将结合我们团队在实际项目上的应用和不断打磨沉淀出来的框架做个简要介绍。

一.整体介绍

如上图,框架本身是基于 Selenium,结合 POM 设计模式和分层思想,并配套日志、配置等常用模块的封装;用例部分基于 Pytest 单元测试框架,结合 yml 用例组织实现数据驱动;报告部分基于 allure 插件。

各部分主要功能:
POM 设计模式:将核心代码分为了四层:元素定位层、页面对象层、测试数据层、测试用例层。其中页面对象层中封装的每个页面类都会继承 BasePage,BasePage 中封装了页面元素的常用操作,比如:等待元素、查找元素、点击元素、获取元素的文本值、鼠标操作、切换窗口等。
测试用例类:使用 pytest,批量执行用例,使用插件 allure 来生成测试报告、收集日志和报错截图。
Configs:是一个配置文件夹,主要为了区分不同运行环境、存储测试账号及其它全局变量
Utils:是一个存放常用工具类的文件夹,封装了一些常用方法,比如:配置文件的读取、接口请求、yml 文件解析、文件上传、日志收集等。

二.具体实现

1.配置文件
使用配置文件的好处?
将所有的代码和配置都变成模块化可配置化,可以提高代码的复用性;这样有数据或代码变动时,不用每次都去修改代码内部。
解决业务场景中的实际问题,比如:我们想实现一套自动化代码在多套测试环境中运行,可以在配置文件中设置全局开关,控制脚本的运行环境;不同配置文件可以管理不同的测试账号、数据库地址等。
全局开关配置文件 global.cfg:

2.yml 文件管理用例数据
运行自动化测试用例是关键,存放测试用例的方式有很多,比如 Excel 表格、xml 文件、json 文件、py 文件等。我们这里用 yml 文件来管理用例数据,优点是通过 key-value 方式维护,可读性强,减少后续维护成本。框架中主要涉及如下 yml 相关处理方法:

在编写 yml 用例文件时,建议一个文件存放一个业务场景的 case,正常场景和异常场景分开维护。比如:登录和注册场景,登录的业务场景会有两个 yml 文件,一个 yml 文件维护正常场景,一个 yml 文件维护异常场景;注册场景也同样处理。

3. PO 设计模式
PO 是 PageObject 的缩写,PO 模式是自动化测试项目开发实践的最佳设计模式之一。核心思想是通过对界面元素的封装,减少代码冗余;同时在后期维护中,若元素定位发生变化,则只需要调整页面元素封装的代码即可。这样可提高测试用例的可维护性和可读性。
按照 PO 设计模式和分层思想,将代码分为四层:
元素定位层:封装页面的元素,注意:不必把页面全部元素封装,封装业务场景使用的即可。
以登录页面为例:

页面对象层:封装页面的业务逻辑,比如:登录页面封装登录功能,注册功能等。

测试数据层:准备场景的测试数据,yml 文件格式存储。以简单的登录场景为例,用例编写如下:

login_success.yml:

login_fail.yml:

测试用例层:跑业务场景,数据驱动,批量执行,断言。

4. 用例执行
使用 pytest 来执行测试用例,pytest 是一个非常成熟的 python 单元测试框架,比 unittest 更灵活,更容易上手。开发 web 自动化项目,pytest 也比 unittest 更合适。
pytest 中自带的有两个文件,一个是 pytest.ini,另一个是 conftest.py。
pytest.ini 是核心配置文件,放在项目根目录下,名称固定,运行时程序自动解析。配置文件中可以改变 pytest 一些默认的运行方式,如:用例收集规则,标签,命令行参数等等。例如:

conftest.py 文件名称固定,不能修改,可放到项目根目录下全局调用,也可放在某个 package 下,仅在该 package 内有效。实际测试中,conftest.py 文件需要结合 fixture 来使用,实现用例的前置和后置。例子如下:

pytest 通过命令行运行用例,可以通过给用例打标签的方式,指定用例来运行;可以设置 case 失败后重跑次数;可以设置并发数;可以设置报告的生成方式等。例如:

三、框架实际使用步骤举例

框架的实际使用,以实际项目上的一个页面功能举例如下:
1.完成元素定位
pages 层按照页面功能划分,存放页面元素定位。

项目中每个页面下封装{name}_page_locator.py,覆盖业务场景所需页面元素

2.封装页面对象类
导入对应页面的元素定位文件和 base_page.py,页面对象类需要结合 BasePage 中封装的方法完成对页面元素的操作。项目中每个页面下有{name}_page.py,封装页面功能。

3.Pytest 组织测试用例(操作页面对象类)
testcases 层存放各模块下的测试用例,test_xxx.py 文件操作页面对象,实现正向和反向业务场景的测试,加上断言,判断用例执行结果。

4.Yml 组织用例数据
data 层存放用例数据,用例编写格式为 yml。正向用例和反向用例分开维护。

5.用例执行
根目录下的 run.py 定义了执行用例的方法,可以指定 case 标签运行。

四.总结

按照这样的方式封装,框架使用就变得非常的清晰,易用性大大提高。且日常功能变动,也仅需修改相关 POM,不影响其它功能,同样框架应用于其它项目的话,也只需完成 POM 相关的修改,可扩展性也还是不错的。基于 Pytest 的用例执行,也便于 CI 的集成;实际运行中,结合 Selenium-Grid,就实现了用例的分布式运行,大大提高执行效率(效率对于 UI 自动化来说,也还是非常重要的)。

此外,对于项目中非常关键的 Pytest 主要特性及与 Unittest 的差异做个补充:


↙↙↙阅读原文可查看相关链接,并与作者交流