关于web UI自动化测试的初探

前言

UI自动化测试是通过编写的脚本发出相应指令给到客户端,进行执行一些模拟用户操作行为的动作集合,减轻测试人员重复繁琐的简单回归测试流程的负担,帮助开发人员测试ui组件库的功能

原理

  1. 浏览器私有协议通信 例如 Chrome devtools protocol

Chrome DevTools Protocol 允许工具对 Chromium,Chrome 和其它基于 Blink 的浏览器进行测试、检查、调试以及配置

{"id":1,"method":"Network.enable","params":{"maxTotalBufferSize":10000000,"maxResourceBufferSize":5000000}}
{"id":2,"method":"Page.enable"}

... ...

{"id":36,"method":"Overlay.highlightNode","params":{"highlightConfig":{"showInfo":true,"showRulers":false,"showExtensionLines":false,"contentColor":{"r":111,"g":168,"b":220,"a":0.66},"paddingColor":{"r":147,"g":196,"b":125,"a":0.55},"borderColor":{"r":255,"g":229,"b":153,"a":0.66},"marginColor":{"r":246,"g":178,"b":107,"a":0.66},"eventTargetColor":{"r":255,"g":196,"b":196,"a":0.66},"shapeColor":{"r":96,"g":82,"b":177,"a":0.8},"shapeMarginColor":{"r":96,"g":82,"b":127,"a":0.6},"displayAsMaterial":true,"cssGridColor":{"r":75,"g":0,"b":130}},"nodeId":4}}
复制代码

chromedevtools.github.io/devtools-pr…

www.wangshaoxing.com/blog/2017-0…

启动chrome浏览器,并暴露出远程控制端口

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check --user-data-dir=$(mktemp -d -t 'chrome-remote_data_dir')
复制代码

puppeteer 是封装devtools protocol 协议,提供了更方便操作的nodejs api,来实现控制浏览器

  2. 浏览器驱动webdriver  例如 chromedriver

我们可以把WebDriver驱动浏览器类比成出租车司机开出租车。 zhuanlan.zhihu.com/p/47831129

在开出租车时有三个角色:

[测试脚本]乘客:他/她告诉出租车司机去哪里,大概怎么走

[浏览器驱动]出租车司机:他按照乘客的要求来操控出租车

[浏览器]出租车:出租车按照司机的操控完成真正的行驶,把乘客送到目的地

框架和工具

  1. Selenium (多语言)

  2. webdriverio (nodejs)

  3. Cypress (nodejs)

  4. macaca (多语言)

  5. ...

Selenium

Selenium 是一个用于Web应用程序测试的工具,测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IEMozilla FirefoxSafariGoogle ChromeOpera等。

这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成

Selenium 由多个软件工具组成,每个具备特定的功能

Selenium 1 (Selenium RC 或 Remote Control) 在很长一段时间内,Selenium RC 都是最主要的 Selenium 项目,直到 WebDriver 和 Selenium 合并而产生了最新且最强大的 Selenium 2. Seleinum 1 仍然被活跃的支持着(更多是维护),并且提供一些 Selenium 2 短时间内可能不会支持的特性,包括对多种语言的支持(Java, Javascript, Ruby, PHP, Python, Perl and C#) 和对大多数浏览器的支持。

Selenium 2 (Selenium Webdriver) Selenium 2 代表了这个项目未来的方向,也是最新被添加到 Selenium 工具集中的。这个全新的自动化工具提供了很多了不起的特性,包括更内聚和面向对象的 API,并且解决了旧版本限制。它支持WebDriver API及其底层技术,同时也在WebDriver API底下通过Selenium 1技术为移植测试代码提供极大的灵活性。此外,为了向后兼容,Selenium 2 仍然使用 Selenium 1 的 Selenium RC 接口。

Selenium IDE (集成开发环境) 是一个创建测试脚本的原型工具。它是一个 Firefox 插件,提供创建自动化测试的建议接口。Selenium IDE 有一个记录功能,能记录用户的操作,并且能选择多种语言把它们导出到一个可重用的脚本中用于后续执行

Webdriverio

Selenium 1 由于它使用了基于 Javascript 的自动化引擎,而浏览器对 Javascript 又有很多安全限制,有些事情就难以实现。更糟糕的是,网站应用正变得越来越强大,它们使用了新浏览器提供的各种特性,都使得这些限制让人痛苦不堪需要一款能通过浏览器和操作系统的本地方法直接和浏览器进行通话的测试工具,来解决Javascript 环境沙箱的问题。WebDriver 项目的目标就是要解决 Selenium 的痛点

Webdriverio 是基于一个基于node的网页自动化测试框架,它封装了 Selenium WebDriver API,可拓展性非常高。相比较原生的Selenium 而言,WebDriverIO 的代码非常的简单易懂,api和方法与jquery相似,非常方便前端上手。同时WebDriverIO 也支持mobile端的测试

Cypress

和 Selenium 的关系(摘自官网译文):

“事实上,Cypress的架构在一些关键方面与Selenium非常不同: Cypress在浏览器的上下文中运行。有了Cypress,检查浏览器中运行的内容变得更容易,但与外部世界对话变得更难。在Selenium中则恰恰相反。Selenium在您的应用程序运行的浏览器外部运行(尽管Cypress每天都添加更多的命令,让您能够访问外部世界——如cy.request()、cy.exec()和cy.task())。 使用Selenium,你可以获得100%的模拟事件(使用Selenium RC)或100%的本地事件(使用Selenium WebDriver)。而cypress,两者都有。在大多数情况下,我们使用模拟事件。然而,我们在cookie之类的东西上使用了自动化api,我们在JavaScript沙箱之外进行扩展,并与底层浏览器api进行交互。这使我们可以灵活地决定在特定情况下使用哪种类型的事件”

Macaca

Macaca 是一套面向用户端软件的测试解决方案,提供了自动化驱动,环境配套,周边工具,集成方案,旨在解决终端上的测试、自动化、性能等方面的问题

示例

Webdriverio

import path from "path";
import { login } from "../helpers/login";

describe('UI test', async () => {
    it('create-task: 创建简单任务', async () => {

        await login(browser);
        const timestamp = Date.now();
        await browser.url('https://xxx.xxx/project/P4702/list');

        const createBtn = await $('.header .k-button')
        await createBtn.click();

        await browser.pause(1000)

        const titleInput = await $('.k-home-new-task-modal-v-2 .task-title__input_box')
        await titleInput.setValue(`[UI-T][${timestamp}] ui自动创建的标题`)

        const descTextArea = await $('.k-home-new-task-modal-v-2 .ql-editor')
        await descTextArea.setValue('ui自动创建的任务描述,ui自动创建的任务描述,ui自动创建的任务描述')

        const submitBtn = await $('.k-home-new-task-modal-v-2 .task-modal__custom-field-wrapper .task-modal__button-group .k-button')
        await submitBtn.click();

        // 检查是否 有必填字段
        const requiredMsg = await $('.k-home-new-task-modal-v-2 .k-error-msg');
        const isExistRequired = await requiredMsg.isExisting();
        if (isExistRequired) {
            await browser.saveScreenshot(path.resolve(__dirname, `../../screenshot/create-task-${timestamp}.png`));
            expect(0).toBe(1)
            return;
        }

    });

    it('task-detail: 任务详情页-创建子任务', async () => {
        await login(browser);
        await browser.url('https://xxx.xxx/task/T592167');

        await browser.pause(2000)

        const subTaskCreateBtn = await $('.k-button.create-task-btn')

        const isExisting = await subTaskCreateBtn.isExisting()

        if (isExisting) {
            await subTaskCreateBtn.scrollIntoView();
            await subTaskCreateBtn.click();
            await browser.pause(2000)
            await browser.keys(['哈哈哈,我是机器人创建的任务', 'Enter']);
        } else {
            expect(0).toBe(1)
        }

    })

    it("task-detail: 任务详情页-侧边栏滚动复位", async () => {
        await login(browser);
        await browser.url('https://xxx.xxx/task/T592167');
        await browser.pause(1000);
        const lastSiderBarBtn = await $('.mini-sidebar a:last-child');
        await lastSiderBarBtn.click();
        await browser.pause(1000);
        const back2TopBtn = await $('.menu-icon-back2top');
        await back2TopBtn.click();
        await browser.pause(300);
        const scrollContainerBox = await $('#scrollContainer')
        const scrollTop = await scrollContainerBox.getProperty('scrollTop');
        expect(scrollTop).toBe(0)
    })
});
复制代码

Cypress

/// <reference types="cypress" />

context('Aliasing', () => {
  beforeEach(() => {
    cy.visit('https://xxx.xxx/');
    cy.setCookie("k-token","b0b4574ab80e059a61fdc18fd9ca7179")
    cy.setCookie("accessproxy_session","9332c36a-85d5-4d9e-be22-2a21d567711e")
    cy.visit('https://xxx.xxx');
  })

  it('测试一下', () => {
    // https://on.cypress.io/as

    // Alias a DOM element for use later
    // We don't have to traverse to the element
    // later in our code, we reference it with @

    cy.get('.header .k-button-group .k-button').as('firstBtn')

    // when we reference the alias, we place an
    // @ in front of its name
    cy.get('@firstBtn').click()

    cy.get('.k-home-new-task-modal-v-2 .task-title__input_box').type(`[UI-T] ui自动创建的标题`)
    cy.get('.k-home-new-task-modal-v-2 .task-modal__custom-field-wrapper .task-modal__button-group .k-button').click();

    // cy.get('@firstBtn')
    //   .should('have.class', 'btn-success')
    //   .and('contain', 'Changed')
  })

})
复制代码

小结

  1. Selenium 自动化测试的鼻祖,支持多语言
  2. webdriverio 在Selenium 通点上基于 node 开发的测试框架,只支持 nodejs 语言
  3. Cypress  不同于 Selenium 和 webdriverio,cypress是直接在浏览器上下文中运行的,测试比较真实,高度集成,简单易上手
  4. macaca 是一个标准化支持多端的测试解决方案,国内阿里开发开源的

参考

www.wangshaoxing.com/blog/2017-0…
zhuanlan.zhihu.com/p/47831129
wizardforcel.gitbooks.io/selenium-do…
blog.csdn.net/loisandyu/a…
docs.cypress.io/faq/questio…
luojun0115.github.io/web_seleniu…

猜你喜欢

转载自juejin.im/post/7125684228167041032