Web UI自动化的设计和实践

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"UI 自动化测试,即通过自动化的手段来控制机器模拟人进行手工操作。随着 GrowingIO 业务的不断发展,新需求的不断增加,回归测试的任务越来越重,现有测试的资源已经不足以应对繁重的回归测试任务,亟需 UI 自动化来代替人手工进行回归测试,解放回归测试的人力去做更精准的测试。因此,引出下文在 GrowingIO 的Web UI 自动化的建设,本文主要就以下两个方面展开介绍:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"框架搭建","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"集成质量平台","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"框架搭建","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"PageObject","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"众所周知,UI 自动化测试,是位于测试金字塔塔尖的位置,ROI 低。其痛点主要体现在:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1.测试用例维护成本高,页面元素定位方式或者布局有一些细微的变动,之前写好的代码可能就有很大的改动;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.代码冗余,复用性低,可读性不好。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对以上痛点,同时也通过大量调研,决定使用 PageObject 设计模式,其核心思想为六大原则:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"公共方法代表页面提供的服务","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不要暴露页面细节","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不要把断言和操作细节混用","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方法可以 Return 到新的页面","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不要把整页内容都放到 PageObject 中","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相同的行为产生不同的结果,可以封装不同结果","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"依据以上六大原则,并结合 GrowingIO 具体业务的情况,目录层级设计如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BasePage 层","attrs":{}},{"type":"text","text":":封装对网页的一些基础操作的方法,比如打开浏览器、查找元素、截屏等","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Component 层","attrs":{}},{"type":"text","text":":继承 BasePage 层,封装了对页面中公共组件的操作方法,比如时间组件","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Page 层","attrs":{}},{"type":"text","text":":继承Component层,该层中的每个方法都对应当前页面的一个功能,方法里可以调用Component 层中的方法或调用 BasePage 层中封装的方法","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"TestCase 层","attrs":{}},{"type":"text","text":":调用业务 Page 层中封装的方法,编写业务 Case,并做断言","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"实际项目的目录分层如下:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\n├── basepage\n│   └── base_page.py\n├── component\n│   └── element_design.py\n├── conf\n│   ├── conf.py\n├── datas\n├── log\n│   └── all.log\n├── log.py\n├── page\n│   ├── home_page.py\n│   ├── login_page.py\n│   ├── main_page.py\n│\n├── pytest.ini\n├── report\n│  \n├── requirements.txt\n├── run_all_cases.py\n├── testcase\n│   ├── conftest.py\n│   ├── testcase.py\n│\n└── util\n └── util.py","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Selenium + Python","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"语言选择 Python,对于新人友好且组内人员比较熟悉,可以迅速上手;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前市场上的 Web UI 自动化测试方案百花齐放,基于底层技术的不同大体上分为以下几类:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1.WebDriver Protocol 类:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如 Selenium 3,WebdriverIO,Protractor,Nightwatchjs","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.Proxy JS 注入类:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如 Selenium RC,TestCafe,Cypress","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3.DevTool Protocol 类:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如 Puppeteer, Playwright t","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们选择使用 Selenium 3,优势如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开源、免费","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"多浏览器支持:Firefox、Chrome、IE、Opera、Edge","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"多平台支持:Linux、Windows、Mac","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"多语言支持:Java、Python、Ruby、C#、JavaScript、C++","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对 Web 页面有良好的支持","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简单(API 简单,API:在类里面封装好的方法,即暴露给别人的一个可用的接口)、灵活(用开发语言驱动)、足够稳定","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最主要的是 Selenium 的 Grid 方案即分布式方案非常成熟,而所谓的分布式就是由一个 Hub 节点和若干个 Node 代理节点组成。Hub 用来管理各个代理节点的注册信息和状态信息,并且接受远程客户端代码的请求调用,然后把请求的命令转发给代理节点来执行,最后再汇总各个代理节点的执行结果返回给远程客户端。无论是与 Jenkins 集成,还是对用例执行时间的要求,分布式执行才是 UI 自动化的最终态,这里使用 docker-compose 来创建 Hub 和 Node 节点","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"docker-compose.yml 文件内容如下:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"version: '3'\n\nservices:\n hub:\n container_name: selenium-hub\n image: selenium/hub\n restart: always\n ports:\n - 4445:4444\n environment:\n HUB_HOST: hub\n health-timeout: 30\n SE_NODE_SESSION_TIMEOUT: 30000\n JAVA_OPTS: -Xmx1024m\n chrome:\n image: selenium/node-chrome-debug:3.141.59-20210311\n container_name: chrome_test\n restart: always\n depends_on:\n - hub\n ports:\n - 4446:5900\n volumes:\n - /etc/hosts:/etc/hosts\n - /dev/shm:/dev/shm\n environment:\n JAVA_OPTS: -Xmx512m\n HUB_HOST: hub\n NODE_MAX_SESSION: 5\n NODE_MAX_INSTANCES: 5\n firefox:\n image: selenium/node-firefox-debug:3.141.59-20210311\n container_name: firefox_test\n restart: always\n ports:\n - 4447:5900\n volumes:\n - /etc/hosts:/etc/hosts\n - /dev/shm:/dev/shm\n depends_on:\n - hub\n environment:\n - JAVA_OPTS=-Xmx512m\n - HUB_HOST=hub\n - NODE_MAX_SESSION=4\n - NODE_MAX_INSTANCES=4","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Grid 模式执行用例的流程图","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/39/393634384fd5e691f856dfda11792f2e.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Pytest","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"管理和组织测试用例的框架选用 Pytest 框架,其优点如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简单灵活,容易上手,文档丰富","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"支持参数化,可以细粒度地控制要测试的测试用例","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具有很多第三方插件,并且可以自定义扩展,比较好用的如allure-pytest(完美测试报告)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以很好的和Jenkins结合","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"说到 Pytest 就不得不提其精髓:Fixture,Fixture 与传统的测试框架的(Setup/Teardown)相比更加灵活:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"按模块化的方式实现,每个 Fixture 都可以互相调用","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Fixture 的作用范围灵活可配置,可以scope参数,指定Fixture的作用域:函数(Function),模块(Module),类(Class),或整个项目(Session),执行顺序为:Session > Module > Class > Function","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本项目中大量使用了@pytest.fixtrue装饰器来装饰方法,被装饰的方法名作为一个参数传入测试方法中,可以使用这种方式来完成测试之前的初始化,也可以返回数据库给测试函数,尤其是跟conftest文件和yield搭配使用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"conftest.py","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"import pytest\nfrom selenium import webdriver\nfrom selenium.webdriver import DesiredCapabilities\n\[email protected](scope='session')\ndef init_driver():\n if browser == \"chrome\":\n driver = webdriver.Chrome()\n elif browser == 'firefox':\n driver = webdriver.Firefox()\n elif browser == 'safari':\n driver = webdriver.Safari()\n elif browser == 'remote':\n capabilities = DesiredCapabilities.CHROME\n driver = webdriver.Remote(command_executor='http://localhost:4445/wd/hub', desired_capabilities=capabilities)\n else:\n driver = ''\n print('浏览器类型暂不支持!!')\n driver_obj = OpBasePage(driver)\n yield init_driver.open_op_url().login_op_by_gui(username, password)\n # 关闭浏览器\n driver_obj.close_browser()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"test_dashboard.py","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\nclass TestDataBoard:\n @pytest.fixture()\n def board(self, init_driver):\n yield init_driver.jump_to_board_by_url()\n\n def test_board_sort(self, board):\n board.click_button_go_to_board_manage().check_board_sort()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从以上2个文件中可以看到,conftest.py 文件中方法名init_driver传入了,test_dashboard.py 文件中的board方法中,board方法被@pytest.fixtrue装饰器装饰后,又传入了test_board_sort测试方法,所以当运行测试方法test_board_sort时,程序执行顺序为","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/10/10e11cabeb4a6255afaa7c690e654c55.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Allure","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Allure 是一款轻量级并且非常灵活的开源测试报告框架。 它支持绝大多数测试框架, 例如 TestNG、Pytest、JUint 等。它简单易用,易于与 Jenkins 集成,展示多次测试用例的趋势情况。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Allure 装饰器:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7c/7ca28ea1306dfd9a3532a73e70654593.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"测试用例中使用","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"import allure\nimport pytest\n\[email protected](\"distribute-analysis\")\nclass TestDistributionAnalysis:\n @pytest.fixture()\n def distribution_analysis(self, init_driver):\n yield init_driver.jump_to_distribution_analysis_by_url()\n\n @allure.story(\"check distribute analysis\")\n def test_analysis_success(self, distribution_analysis):\n with allure.step(\"create chart\"):\n distribution_name, save_toast, distribute_detail_analysis = distribution_analysis.click_button_to_create_distribute_analysis().create_distribution_analysis()\n distribution_list_name, distribute_analysis = distribute_detail_analysis.click_crumb_to_distribution_analysis().get_first_distribution_chart_name()\n assert distribution_name == distribution_list_name, '新建分布分析单图后未展示在列表页'\n with allure.step(\"delete chart\"):\n distribute_analysis.delete_first_distribution_chart()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"测试报告样例","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f919b67ba9b5ae0bfc492ecf6ea54b2.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"嵌入截图的失败用例样例","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/93/9369221f74cf46f1468e8ae960ec31f2.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,Web UI 自动化框架(PageObject + Selenium + Pytest + Allure)搭建完成,框架整体的执行流程如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c7/c78bd5b182397432655a08f4efd7616b.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"集成质量平台","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"自动化框架搭建完成,但这仅仅是第一步,为了便于跟踪和验证自动化发现的问题,又将自动化框架与自研的质量平台进行集成,并与飞书和 Jira 打通,形成一个完整可追踪的闭环流程,具体流程如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1.在质量平台的页面上,选择测试环境地址和项目 ID,然后点击【启动 Web UI 测试】按钮,即在选定的测试环境和项目下,执行自动化用例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2.自动化用例执行完成,会发送飞书通知,并且自动爬取每一条失败用例的数据,展示在质量平台上","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3.测试人员检查,剔除掉非bug的用例,勾选剩余数据,点击【提交 BUG 】按钮,即自动在 Jira 上,批量创建 sub-bug 并指派给对应的开发人员","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4.当开发人员修改完成后,重复步骤1~3,直到测试用例全部通过","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"集成质量平台后的流程图","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/80a3041185d802b1f11d1d75d598e76e.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"总结","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要介绍了 Web UI 自动化在 GrowingIO 的框架搭建和集成质量平台两大部分,整体的一个思路就是:首先,选择合适的框架并落地,其次就是,自动化发现的问题,要及时跟踪和验证,让整个流程形成一个完整的闭环。当然上文提到的 Web UI 自动化的搭建和集成质量平台的整个流程,一定还存在诸多需要打磨的地方,希望大家不吝赐教。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8b/8b2c03af9069d21ab641c1a963844ee9.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章