极狐GitLab自动化测试指南05——UI测试

1 理论篇

1.1 什么是UI测试

WIKI百科对于UI测试的解释是:

图形用户界面测试是测试产品的图形用户界面(GUI)以确保其符合其规格的过程。这通常是通过使用各种测试用例来完成的。

按照UI测试的目的,可分为逻辑测试和视觉测试:

  • 逻辑:主要指通过操作用户界面,如移动鼠标、点击按钮、输入文本等事件测试软件用户界面的反馈是否符合预期。
  • 视觉:主要指检查用户界面上的文案、字体、字号、布局、颜色等设计元素是否符合预期。

通常来说,通过自动化手段做UI测试,应更多使用在逻辑测试的场景里,而视觉测试更多依靠人工来处理。

按照应用程序部署的平台不同,一般分为基于手机等移动设备的APP、基于B/S架构的Web应用、基于C/S架构的桌面应用(包括运行在硬件终端上的程序,如ATM机、自动购物机等)。

此外WIKI百科还对UI测试的难点进行了描述:

为了生成一组测试用例,测试设计人员尝试涵盖系统的所有功能并完全执行GUI本身。完成此任务的难度有两个:处理域大小和序列。

与 CLI(命令行界面)系统不同,GUI 可能具有需要测试的其他操作。一个相对较小的程序,如微软写字板有325个可能的GUI操作。在大型程序中,操作数量可以很容易地大一个数量级。

第二个问题是排序问题。系统的某些功能只能通过一系列 GUI 事件来完成。例如,要打开文件,用户可能首先必须单击“文件菜单”,然后选择“打开”操作,使用对话框指定文件名,并将应用程序集中在新打开的窗口上。增加可能的操作数量会使排序问题呈指数级增长。当测试人员手动创建测试用例时,这可能会成为一个严重的问题。

此外,测试人员在必须进行回归测试时面临更多困难。

为解决这些问题,UI自动化测试成为了行业内的大趋势,因为自动化测试的优势就是代替频繁的重复性操作,适合解决在大量测试用例下进行回归测试的难题。

1.2 开展UI自动化测试的条件

虽然UI自动化测试有着其不可替代的优势,但在企业内优先开展UI自动化测试仍是不推荐的。《Selenium 2自动化测试实战》一书中介绍了什么样的项目适合自动化测试,列出了10个条件:

  1. 任务测试明确,不会频繁变动
  2. 每日构建后的测试验证
  3. 比较频繁的回归测试
  4. 软件系统界面稳定,变动少
  5. 需要在多平台上运行的相同测试案例、组合遍历型的测试、大量的重复任务
  6. 软件维护周期长
  7. 项目进度压力不太大
  8. 被测软件系统开发比较规范,能够保证系统的可测试性
  9. 具备大量的自动化测试平台
  10. 测试人员具备较强的编程能力

可以看到每一个条件或是凸显UI自动化测试的优势,如频繁回归、大量重复任务等;或是避免UI自动化测试的劣势,如项目相对稳定、需求变动较少、测试人员具备一定的编程能力等。其目的都是为了获得较高的投入产出比,这也是测试金字塔所表达的核心思想。

需要说明的是这10个条件和开展UI自动化测试不是充分必要关系,只是用来参考和评估,毕竟每个企业、每个团队对ROI的要求也是不一样的。

另外按照个人经验,这10个条件里最主要的是需求和界面不能够频繁变动。从时机来看,频繁变动不利于自动化测试发挥替代重复工作的优势;从环境来看,频繁变动不具备开展其他工作的土壤;从人员来看,频繁变动会影响开发和测试人员的心态。属于天时地利人和三不靠,在这样的项目里开展UI自动化测试有较高的风险和失败的几率。

1.3 如何做UI测试

正如前文所说,因为一个应用程序的UI操作逻辑往往很复杂,并且有多重排列组合方式,所以UI测试的用例数量会非常庞大,即使自动化工具可以替代重复操作,但初期编写测试用例还是需要依靠测试人员,如何降低这个工作量?

个人经验是不需要过度追求UI测试用例的高覆盖率,应该把更多精力投入在单元测试、接口测试上,而在UI测试方面,覆盖常规的、主要的业务流程即可。参考28原则,把核心的、相对稳定的主流程通过自动化手段实现,那么相当于做了自动化的冒烟测试。

相较于自动化测试的优势,它的劣势同样明显,工具是人写的,所以自动化测试不适合发现新的Bug。这时候就需要手动测试互补,通过手动测试进行探索性测试,并且把手动测试发现的一些问题编写为测试用例并集成到自动化测试脚本中,不断丰富自动化测试脚本。所以自动+手动,回归+探索的组合式测试方案是行业的主流做法。

UI自动化测试主要用来做回归测试,所以他的运行时机主要有三种:

  • 当应用程序的后台、前端发生变化时,主要指提交应用程序代码并发布到测试环境后,触发UI自动化测试,以验证本次代码提交、程序部署是否存在问题。
  • 定时执行,设置一个时间计划,定时触发UI自动化测试,以验证程序运行一段时间或进行一些操作后是否存在问题。
  • 手动执行,按需运行UI自动化测试。

UI自动化测试的运行模式有两种:

  • GUI模式:应用程序运行在真实的设备上,如电脑、手机、硬件终端,测试脚本也在该设备上执行,操作应用程序的GUI进行测试。测试期间该设备GUI独占,不允许进行其他操作,否则会影响测试,所以测试任务只能顺序执行。
  • Headless模式:主要指依靠浏览器的能力使Web应用无UI的运行在容器中,如使用Selemium测试Web应用时,可以使用Chrome的Headless模式,由于运行在容器里,所以Headless模式可以并发执行。

2 实践篇

2.1 极狐GitLab集成Selenium

2.1.1 编写测试脚本

以Python开发的Selenium测试脚本为例,以下代码实现了基于Chrome的Headless模式运行Selenium,包含两个测试用例,分别是模拟点击https://www.oursky.com/网站的header__logoheader__cta元素,找不到该元素时测试用例不通过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
"""
A simple selenium test example written by python
"""

import unittest
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from HtmlTestRunner import HTMLTestRunner

class TestTemplate(unittest.TestCase):
"""Include test cases on a given url"""

def setUp(self):
"""Start web driver"""
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument("--window-size=1920,1080")
self.driver = webdriver.Chrome(options=chrome_options)
self.driver.implicitly_wait(10)

def tearDown(self):
"""Stop web driver"""
self.driver.quit()

def test_case_1(self):
"""Find and click top-left logo button"""
try:
self.driver.get('https://www.oursky.com/')
el = self.driver.find_element(By.CLASS_NAME, 'header__logo')
el.click()
except NoSuchElementException as ex:
self.fail(ex.msg)

def test_case_2(self):
"""Find and click top-right Start your project button"""
try:
self.driver.get('https://www.oursky.com/')
el = self.driver.find_element(By.CLASS_NAME, "header__cta")
el.click()
except NoSuchElementException as ex:
self.fail(ex.msg)

if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TestTemplate)
runner = HTMLTestRunner(combine_reports=True, report_name="index", add_timestamp=False, output='reports')
runner.run(suite)

2.1.2 自动执行测试

将以上测试脚本放在极狐GitLab代码仓上进行管理,并创建GitLab CI/CD脚本,运行该脚本需Docker/K8S类型的GitLab Runner,参考示例.gitlab-ci.yaml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
stages:         
- test
- report

# 运行Selenium自动化测试
selenium-test-job:
stage: test
image: joyzoursky/python-chromedriver
script:
# 安装Python Selenium环境
- pip install selenium
# 安装HTML测试报告插件
- pip install html-testRunner
- python test_script.py
# 上传HTML测试报告
artifacts:
paths:
- reports

# GitLab Pages展示测试报告
pages:
stage: report
script:
- mkdir ./public
- mv ./reports/* ./public/
artifacts:
paths:
- public

按照UI自动化测试的运行时机,对应三种不同的情况:

  1. 当应用程序代码变更后触发测试:可在上游应用程序的CI/CD脚本中增加selenium测试项目为下游流水线,当上游应用程序代码变并更运行流水线时,会在部署完成后自动触发selenium测试项目的流水线,以执行自动化测试,从而验证应用程序本次代码变更是否可以通过回归测试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    stages:          
    - build
    - test
    - deploy
    - ui-test

    build-job:
    stage: build
    script:
    - echo "Compiling the code..."
    - echo "Compile complete."

    unit-test-job:
    stage: test
    script:
    - echo "Running unit tests... This will take about 1 seconds."
    - sleep 1
    - echo "Code coverage is 90%"

    deploy-job:
    stage: deploy
    script:
    - echo "Deploying application..."
    - echo "Application successfully deployed."

    # 触发下游流水线
    seleniumjob:
    stage: ui-test
    trigger:
    project: mycompany/test-automation/ui-test-selenium
    strategy: depend
  2. 定时执行测试:可在项目的“CI/CD——计划”中创建定时任务以执行自动化测试。

  3. 手动执行测试:可在项目的“CI/CD——流水线”中点“运行流水线”按钮触发流水线构建。

2.1.3 查看测试报告

在上述配置中,已将Selenium的测试报告以HTML格式导出,上传到GitLab制品仓,并通过GitLab Pages展示,可在该项目“设置—Pages”中找到URL链接并访问。

2.2 极狐GitLab集成Squish

2.2.1 安装GitLab Runner

在Squish中进行UI自动化测试就不能使用Headless模式了,需要专机专用,整体流程如下图所示:

所以需要在测试机上安装Squish,用于运行测试脚本。同时需要在测试机上安装并注册GitLab Runner,具体可参考Install GitLab Runner | GitLab , 支持x86, AMD64, ARM64, ARM, s390x, ppc64le等架构、支持Linux, Windows, macOS, FreeBSD等操作系统,支持CentOS, Debian, Ubuntu, RHEL, Fedora, Mint等Linux发行版。

注册Runner时需要给Runner设置一个Tag,用于区分,如Squish for X

需要记录测试机的Squish安装路径、许可证路径、Squish Server的端口,后续配置流水线脚本时使用。

2.2.2 编写测试脚本

以使用Squish for QT测试QT桌面端程序为例,安装Squish、录制脚本、编写脚本,可参考Squish官方文档froglogic Squish Manual

编写测试用例,简单来说分3步:

  1. 设置路径:设置待测试的应用程序路径。
  2. 开启录制:按照测试流程操作应用程序,如点击按钮、输入等,随后自动生成测试脚本。
  3. 调整脚本:脚本支持Java、Python、JS、Ruby等多种语言,使其符合实际需求。

最后将整个测试项目上传到GitLab进行保存和版本控制。

2.2.3 自动执行测试

基于上述测试项目,创建流水线脚本,参考示例.gitlab-ci.yaml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
variables:
SQUISH_DIR: "/xx/xx/xx" # 测试机Squish安装路径
SQUISH_LICENSEKEY_DIE: "/xx/xx/xx" # 测试机Squish 许可证路径
SQUISH_SERVER_PORT: 4325 # 测试机Squish Server Port

squish-tests:
stage: test
tag: Squish for X # 测试机Runner Tag
script:
- echo "Starting VNC Server"
- vncserver :$DISPLAY_NO
- echo $SQUISH_DIR
- echo "Starting squishserver on port=$SQUISH_SERVER_PORT..."
- $SQUISH_DIR/bin/squishserver --port $SQUISH_SERVER_PORT 1>server.log 2>&1 &
- sleep 5
- echo "Register AUT..."
- $SQUISH_DIR/bin/squishserver --port $SQUISH_SERVER_PORT --config addAUT addressbook $SQUISH_DIR/examples/qt/addressbook
- echo "Starting tests..."
# 运行当前目录下的测试用例并生成测试报告
- $SQUISH_DIR/bin/squishrunner --port $SQUISH_SERVER_PORT --testsuite ~/ --exitCodeOnFail 13 --reportgen junit,junit_report.xml --reportgen html,web_report
after_script:
- echo "Stopping squishserver..."
- $SQUISH_DIR/bin/squishserver --stop --port $SQUISH_SERVER_PORT &
- echo "Stopping VNC Server..."
- vncserver -kill :$DISPLAY_NO
- sleep 5
artifacts:
when: always
# 生成JUnit格式报告,并在GitLab 合并请求中展示
reports:
junit: junit_report.xml
paths:
- server.log
- junit_report.xml
# 生成HTML格式报告
- web_report/

# GitLab Pages展示HTML测试报告
pages:
stage: report
script:
- mkdir ./public
- mv ./web_report/* ./public/
artifacts:
paths:
- public

运行流水线,观察是否可以正常运行,需注意运行自动化测试期间不要在测试机上进行其他操作,以免引起测试失败。

2.2.4 查看测试报告

在上述配置中,同时生成了XML和HTML格式的测试报告,并且把JUnit格式XML与GitLab的集成,实现在合并请求中查看Squish的测试结果,实现方式可参考 Unit test report examples | GitLab

同时测试报告也以HTML格式导出,上传到GitLab制品仓,并通过GitLab Pages展示,可在该项目“设置—Pages”中找到URL链接并访问。

结束语

回顾之前的4篇文章,从测试的发展史、方法论、工具到具体的接口测试、性能测试、单元测试再到这篇UI测试,也仅仅是概括性的介绍了软件测试很小的一部分内容。软件测试在软件开发过程中依然是不可或缺的重要组成部分,它的实践落地依然是要结合企业实际的环境、时机、人员能力去综合考虑,在摸索中前进。

而对于极狐GitLab来说,主要是通过两方面将软件测试更好的融入DevOps体系:

  1. 通过极狐 GitLab 的 CI/CD把自动化测试工具集成起来。目的是要实现全面的自动化测试。开发人员提交代码或者测试脚本更新之后,就可以通过 CI/CD 立刻触发一次全面的回归测试,才能彻底解决效率问题。
  2. 通过极狐GitLab的代码合并请求将测试结果汇总起来。目的是作为代码评审的依据,作为质量门禁的载体。真正做到人人参与评审、人人为质量负责。

关于极狐GitLab与自动化测试实践的相关内容到这里就全部结束了,完结撒花。


参考资料

极狐GitLab自动化测试指南05——UI测试

https://wurang.net/auto-test05/

作者

Wu Rang

发布于

2022-08-25

更新于

2022-09-01

许可协议

评论