4 Star 23 Fork 13

嘉诚开源 / jc-uitest

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

嘉诚UI自动化测试框架

框架介绍

嘉诚ui自动化测试框架集成了playwright和pytest,提供简单、快捷、可视化的用例录制手段,以及结果统计、报告生成、持续构建等特性,实现UI自动化测试的全链路解决方案。

安装部署

依赖环境

软件 版本 备注
操作系统 win7及以上; centos7及以上 centos系统要求:CLIBC版本为2.18+,字符集为zn_CN.UTF8
python v3.7+
pip/pip3 v22.0.3+

PS:可使用命令:python -m pip install --upgrade pip,升级pip/pip3版本。

代码下载

将UI自动化框架代码下载到本地,gitee地址:https://gitee.com/jiachengnet/jc-uitest。

本地部署

  • 用VSCode或Pycharm打开本地项目代码,根目录下的requirements.txt文件中有UI自动化测试所用的所有依赖包,终端中执行命令即可安装:
$ pip install -r requirements.txt
  • 安装浏览器驱动
python -m playwright install

说明:以上步骤操作完毕后,可在本地运行测试框架自带的测试用例,检验环境是否安装成功。

框架介绍

框架文件结构

jc-uitest									# UI自动化测试工程
├── logs								# 脚本执行日志
├── testCases							# 测试用例存放路径
│   ├── login							# 功能模块名
│        └── test_login.py				# UI测试用例-登录系统
│   ├── test_baidu.py					# UI测试用例-访问百度
│   └ ──data.json						# 存放参数化的数据(若不使用参数化,此文件可忽略)
├── tools								# 存放公共方法的目录
├── report								# 每次运行均可在此目录下生成测试报告,包含:错误日志时的屏幕截图、html格式的报告
├── requirements.txt					# 所有UI自动化测试实施时所需的依赖环境
├── config.py							# UI自动化测试框架的配置文件,可配置浏览器驱动类型等
├── conftest.py							# UI自动化测试框架的自带的底层方法
├── webserver.py						# 启动后可通过点击企业微信通知中报告地址查看测试报告内容
└── run.py								# 批量运行全部/部分用例

工程配置项说明

配置名称 说明 默认值
1 browser 浏览器驱动类型,支持chromium, firefox, webkit browser = "chromium"
2 mode 用例运行模式,包括headless和headedheadless:无头模式,运行用例时不弹出浏览器;headed:有头模式,运行用例时,弹出浏览器 mode = "headless"
3 rerun 失败重跑次数 rerun = "0"
4 fail 当达到最大失败数,停止执行 max_fail = "5"
5 notice_status 是否开启企业微信消息通知。开启企业微信通知时,设置为TRUE;否则,则不开启企业微信通知 notice_status=True
6 chatbot_url 企业微信机器人地址
7 product_name 产品名称及版本号 product_name="嘉城中台v21.10版本"
8 project_name 项目名称(gitlab项目名称) project_name = "jcmp_uitest"
9 server_address 测试报告地址(测试服务器ip地址+webserver端口号) server_address = "http://172.31.6.10:8000"

测试用例介绍

"""
编写人
编写时间
"""
#引入脚本所用的模块
import os
import sys
import time
from playwright.sync_api import Page
import pytest
from os.path import dirname, abspath
from tools.get_log import GetLog
from tools.read_json import get_data

#指定参数化文件路径
logincommon_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
sys.path.insert(0, logincommon_path)
logger = GetLog.get_log()

#添加装饰器,实现测试用例参数化
@pytest.mark.parametrize(
    "url,loginname,password",
    get_data(logincommon_path + "/data.json","login")
)


#定义测试用例中使用的方法,引用参数化文件中的参数
def test_login(page: Page, url,loginname, password):
    """
    用例名称:用户中心登录;
    用例步骤:
      1)输入用户中心地址,访问用户中心;
      2)输入用户名、密码。点击登录按钮;
      3)登录成功后,判断系统名称是否为“嘉城开发平台”;
      4)点击退出登录
    """


	#获取当前正在执行的测试用例名称,以日志形式打印出来
    casename = os.path.splitext(os.path.basename(__file__))[0]
    logger.info("正在执行用例:{}".format(casename))

	#以下为测试用例中具体的操作步骤
    # Go to http://test-env.jcinfo.com/jcdp/
    page.goto(url)

    # Click [placeholder="请输入账号"]
    page.click("[placeholder=\"请输入账号\"]")

    # Fill [placeholder="请输入账号"]
    page.fill("[placeholder=\"请输入账号\"]", loginname)

    # Click [placeholder="请输入密码"]
    page.click("[placeholder=\"请输入密码\"]")

    # Fill [placeholder="请输入密码"]
    page.fill("[placeholder=\"请输入密码\"]", password)

    # Click input[type="submit"]
    # with page.expect_navigation(url="http://test-env.jcinfo.com/jcmms/#/404"):
    with page.expect_navigation():
        page.click("input[type=\"submit\"]")

    # 添加断言:系统登录成功后,获取并判断浏览器标题是否为“嘉诚开发平台”,如果不是,则抛出异常
    try:
        assert "嘉诚开发平台" == page.text_content(".avue-logo_title")
        logger.info("用例{}的断言结果为{}".format(casename, "嘉诚开发平台" == page.text_content(".avue-logo_title")))
    except Exception as e:
        logger.error("用例{}的断言结果为{},错误信息是:{}".format(casename, "嘉诚开发平台" == page.text_content(".avue-logo_title"), e))
        raise

    # Click span[role="button"]
    page.click("span[role=\"button\"]")

    # Click text=退出登录
    page.click("text=退出登录")

    # Click [aria-label="提示"] button:has-text("确定")
    with page.expect_navigation():
        page.click("[aria-label=\"提示\"] button:has-text(\"确定\")")

    # Close page
    page.close()

开发测试用例

录制用例

  • 在cmd或编辑器的终端中,进入到UI自动化测试工程的testCases目录;

  • 执行录制命令,如:浏览器输入地址为http://test-env.jcinfo.com/jcdp,将录制生成的文件名称指定为test_userCenter_login.py,可输入以下命令

    python -m playwright codegen -o test_userCenter_login.py http://test-env.jcinfo.com/jcdp
  • 录制完毕后关闭浏览器,录制内容可自动保存至文件中,内容如下:

    from playwright.sync_api import Playwright, sync_playwright
    
    def run(playwright: Playwright) -> None:
        browser = playwright.chromium.launch(headless=False)
        context = browser.new_context()
    
        # Open new page
        page = context.new_page()
    
        # Go to http://test-env.jcinfo.com/jcdp/
        page.goto("http://test-env.jcinfo.com/jcdp/")
    	# Click [placeholder="请输入账号"]
    	page.click("[placeholder=\"请输入账号\"]")
        .....
    	# Close page
        page.close()
    
        # ---------------------
        context.close()
        browser.close()
    
    
    with sync_playwright() as playwright:
        run(playwright)
  • 双击录制生成的脚本文件可以回放整个录制过程,检查是录制内容是否正确。

说明:UI自动化测试用例文件名称需以“test_”开头,否则工程中将不会执行此用例。

编辑用例

引入工程包

使用pycharm或VSCode打开UI自动化测试工程,在录制好的脚本最上方,添加引入工程包的语句(不需要修改,直接复制即可)

import os
import sys
import time
import pytest
from playwright.sync_api import Page
from os.path import dirname, abspath
from tools.get_log import GetLog
from tools.read_json import get_data
参数化

测试用例中经常使用的变量(如:网址、用户名、密码等),可放在testCases目录下得data.json文件中,每个测试用例均可引用此变量作为方法的参数使用。若用例需要更换用户名及密码进行登录,则不需要修改用例本身,可直接修改data.json文件中的参数值即可。

如:将登录时使用的网址、用户名、密码配置在testCases\data.json文件中

{
  "login":
  [
    {
      "url":"http://test-env.jcinfo.com/jcdp/",
      "loginname": "super",
      "password": "admin12345"
    }
  ]
}

在测试用例文件中,定义方法上方增加指定参数化文件路径及参数注入的语句(不需要修改,直接复制即可):

logincommon_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
sys.path.insert(0, logincommon_path)
logger = GetLog.get_log()

@pytest.mark.parametrize(
    "url,loginname,password",
    get_data(logincommon_path + "/data.json","login")
)

在测试用例文件中,定义方法时传入并使用用户名参数、密码参数(定义方法后,在注释中说明测试用例名称及步骤):

def test_login(page: Page,url, loginname, password):

    """
	用例名称:按照登录账户查询用户;
	用例步骤:
    1)登录系统;
    2)进入用户中心-系统管理-用户管理页面;
    3)登录账户查询条件中输入“super”,点击查询;
    4)点击退出登录
	"""

    # Go to http://test-env.jcinfo.com/jcdp/
    page.goto(url)

    # Click [placeholder="请输入账号"]
    page.click("[placeholder=\"请输入账号\"]")

    # Fill [placeholder="请输入账号"]
    page.fill("[placeholder=\"请输入账号\"]", loginname)

    # Click [placeholder="请输入密码"]
    page.click("[placeholder=\"请输入密码\"]")

    # Fill [placeholder="请输入密码"]
    page.fill("[placeholder=\"请输入密码\"]", password)

    # Click input[type="submit"]
    with page.expect_navigation():
        page.click("input[type=\"submit\"]")

说明: 测试用例文件若不使用参数化方式对变量进行设置,则变量值发生变化时直接在测试用例文件中修改即可。

添加断言

在录制生成的脚本中,需要根据用例添加对应的断言

#系统登录成功后,获取并判断浏览器标题是否为“嘉诚开发平台”,如果不是,则抛出异常
assert "嘉诚开发平台" == page.text_content(".avue-logo_title")
注释或删除无用代码

录制生成的脚本中,需要将以下代码注释或删除,脚本才可运行成功。

# browser = playwright.chromium.launch(headless=False)
# context = browser.newContext()
# page = context.newPage()

 # context.close()
    # browser.close()

# with sync_playwright() as playwright:
#     run(playwright)

本地调试用例

  • 运行所有用例,可在终端中执行
$ python run.py testCase
  • 运行某个功能模块中的所有用例,可在终端中执行
$ python run.py 功能模块名称
  • 运行单个脚本,需要进入到此用例所在目录
$ python run.py 功能模块名称\用例文件名称

说明:

  1. 控制台中可输出脚本执行成功及失败情况,具体失败原因可查看log文件或report;
  2. 执行脚本时,可在命令行中指定运行模式(headed/headless)、测试服务器地址、是否开启企业微信通知,若不指定,则按照config.py文件中默认配置执行。如:python run.py testCases mode:headed server_address:http://uitest.jcinfo.com notice_status:True。

部署测试工程

UI自动化测试工程中,根据测试工程在测试服务器中的路径,修改gitlab-ci.yml文件

gitlab-ci

执行测试及结果通知

执行测试

  • 本地执行:在编辑器的终端中执行命令即可实现本地执行,如执行:python run.py testCases;
  • 服务端构建执行:通过配置DevOps实现自动构建并执行;
  • 定时执行:请联系产品支持和质控中心团队,在服务端设置执行测试的定时任务。

企业微信配置群机器人

UI自动化测试用例代码提交至gitlab,流水线构建完毕后,测试服务器每日定时执行UI自动化测试,采用企业微信机器人通知模式,群机器人配置方法可参考如下:

bot01 bot02 bot03

配置config.py文件

  • max_fail:当达到最大失败数时,自动停止继续执行其余用例;
  • notice_status:是否开启企业微信通知,开启企业微信通知时,设置为TRUE;否则,则不开启企业微信通知,用例运行完毕后不会发送企业微信进行通知;
  • chatbot_url:配置企业微信群机器人的Webhook地址;
  • product_name:执行UI自动化测试的产品名称(建议命名方式:产品名称+版本号,如:低代码开发平台V21.10版本);
  • project_name:项目名称(gitlab中代码仓库名称);
  • server_address:测试服务器地址(测试服务器ip地址+webserver端口号)。
modifyConfig

启动webserver服务

  • 若本地调试代码时,可不启动webserver服务,执行结果直接在report文件夹中查看;
  • 若需独立部署整个自动化测试环境,可启动webserver服务,消息通知中的报告地址可根据部署情况,在conftest.py中的“企业微信消息通知方法”中配置。

启动webserver服务方法:确认webserver使用的端口号(默认为8000,可根据情况修改)没有被占用后,进入webserver.py文件所在目录,执行以下命令:

#windows系统服务器上执行此命令
python webserver.py
 
#linux系统服务器上执行此命令(断开连接时,webserver不会中断)
nohup python3 webserver.py &

通知结果展示

按照以上方式配置完成后,在服务器或本地运行脚本,企业微信中将收到群机器人发送的UI自动化测试结果通知的消息,点击报告地址可查看本次测试报告的详细情况。

常用方法

常用断言

  • page.text_content("nav:first-child"):获取文本内容;
  • page.get_attribute("input", "alt"):获取属性值;
  • page.is_checked("input"):获取checkbox状态;
  • page.is_visible("input"):是否可见;
  • page.is_enabled("input"):是否可不输入。

更多断言方法可参考:https://playwright.dev/python/docs/assertions。

元素定位

  • path方式定位:page.click("xpath=//h2")或page.click("//h2")
  • 文本方式定位:page.click("text=退出登录")或page.click("'退出登录"')
  • CSS方式定位:page.click("css=h2")或page.click("h2")

更多元素定位方法可参考:https://playwright.dev/python/docs/selectors。

输出日志

  • 在定义方法上方添加以下语句(不需要修改,直接复制即可)

    logger = GetLog.get_log()
  • 在定义方法后,获取当前用例名称,输出显示在日志中;

  • 断言中也需要输出日志,描述失败原因,如:

#获取当前用例名称,打印在日志中
casename = os.path.splitext(os.path.basename(__file__))[0]
logger.info("正在执行用例:{}".format(casename))
 
#断言中输出日志,描述失败原因
logger.info("用例{}的断言结果为{}".format(casename, "嘉诚开发平台" == page.text_content(".avue-logo_title")))

常见问题及解决办法

浏览器驱动未安装或版本不正确

问题描述:若浏览器驱动未安装或版本不正确时,执行脚本时会报以下错误: problem01

解决办法:使用上文提到的命令,下载正确版本的浏览器驱动。

页面未加载完全,导致断言中获取元素内容失败

问题描述:运行用例时,由于操作过快,页面未加载完全,获取的断言不正确,导致脚本运行失败。

解决办法:引入sleep方法,在对应的操作步骤或断言前添加等待时间(等待时间以秒为单位)。

#引入sleep方法块
from time import sleep
 
#对应的操作步骤或断言前添加等待时间
sleep(2)
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

嘉诚UI自动化测试框架集成了playwright和pytest,提供简单、快捷、可视化的用例录制手段,以及结果统计、报告生成、持续构建等特性,实现UI自动化测试的全链路解决方案。 展开 收起
Python
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Python
1
https://gitee.com/jiachengnet/jc-uitest.git
git@gitee.com:jiachengnet/jc-uitest.git
jiachengnet
jc-uitest
jc-uitest
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891