前端测试及相关工具介绍

2019-01-06
test
2537

测试的好处:

  • 保障代码质量和功能的实现的完整度
  • 提升开发效率,在开发过程中进行测试能让我们提前发现 bug ,此时进行问题定位和修复的速度自然比开发完再被叫去修 bug 要快许多
  • 便于项目维护,后续任何代码更新也必须跑通测试用例,即使进行重构或开发人员发生变化也能保障预期功能的实现

当然,凡事都有两面性,好处虽然明显,却并不是所有的项目都值得引入测试框架,毕竟维护测试用例也是需要成本的。对于一些需求频繁变更、复用性较低的内容,比如活动页面,让开发专门抽出人力来写测试用例确实得不偿失。

而那些适合引入测试场景大概有这么几个:

  • 需要长期维护的项目。它们需要测试来保障代码可维护性、功能的稳定性
  • 较为稳定的项目、或项目中较为稳定的部分。给它们写测试用例,维护成本低
  • 被多次复用的部分,比如一些通用组件和库函数。因为多处复用,更要保障质量

这里从单元测试页面功能测试两个方面展开讨论

单元测试

对代码的模块测试,比如函数、接口等

单元测试又有不同的测试风格,主要有TDD,BDD

TDD

TDD是Test Driven Development 的缩写,也就是测试驱动开发。 TDD需要遵循如下规则:

  • 写一个单元测试去描述程序的一个方面。
  • 运行它应该会失败,因为程序还缺少这个特性。
  • 为这个程序添加一些尽可能简单的代码保证测试通过。
  • 重构这部分代码,直到代码没有重复、代码责任清晰并且结构简单。
  • 持续重复这样做,积累代码。

但前端开发中,除了一些框架和库,愿意去写单测的少之又少。另外单测维护成本较高,而且也没法满足前端测试的所有需求。

BDD

从业务的角度定义具体的,以及可衡量的目标 找到一种可以达到设定目标的、对业务最重要的那些功能的方法 然后像故事一样描述出一个个具体可执行的行为。其描述方法基于一些通用词汇,这些词汇具有准确无误的表达能力和一致的含义。例如,expect, should, assert 寻找合适语言及方法,对行为进行实现 测试人员检验产品运行结果是否符合预期行为。最大程度的交付出符合用户期望的产品,避免表达不一致带来的问题

测试框架和断言

框架就是记录测试测哪些模块,以及测试结果。框架在运行时,会检测内部代码的返回值,一旦有false就失败,为true则进行下一条,都为true,则测试通过,如果是异步操作,需等待内置函数回调函数执行,或者超时。 所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。

常用的测试框架: Jasmin、Qunit、Mocha

常用的断言库:assert、should、expect、chai

测试框架--Mocha

  • describe():描述场景,在里面可以设定Context,可包括多个测试用例,也可以嵌套场景
  • it():位于场景内,描述测试用例
  • before():所有测试用例的统一前置动作
  • after():所有测试用例的统一后置动作
  • beforeEach():每个测试用例的前置动作
  • afterEach():每个测试用例的后置动作

具体可以看另一篇文章 mocha + chai + supertest 测试 node server

自动化测试

puppeteer

Puppeteer是谷歌官方出品的一个通过DevTools协议控制headless Chrome的Node库。可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进行UI Test或者作为爬虫访问页面来收集数据。

优点:

所有API集成在一个node库中,环境配置简单 异步操作支持async await,事件可控制

const puppeteer = require('puppeteer');

(async () => {
    // 打开浏览器对象
    const browser = await puppeteer.launch({
        // 有界面
        headless: false,
        // 窗口大小
        defaultViewport: {
            width: 1200,
            height: 800,
        },
        // 模拟操作停顿时间,不然就一瞬间完成
        slowMo: 120,
    });
    // 新建一个页面
    const page = await browser.newPage();
    // 页面内模拟用户操作
    await page.goto('http://localhost:6789');

    await page.waitForSelector('#main > div > div.sider.ant-layout-sider > div > ul > li:nth-child(2)');
    await page.click('#main > div > div.sider.ant-layout-sider > div > ul > li:nth-child(2)');

    await page.click('#main > div > div.content.ant-layout-content > div.content-body > div > div > form > div.ant-row-flex.ant-row-flex-center > button:nth-child(2)');

    // 关闭浏览器
    await browser.close();
})();

在开发中需要注意一下几点

  • 关键位置最好加Id,便于拾取
  • 每个新页面都是独立的,cookie等信息不共用
  • 在模拟用户操作之前,最好确保selector已存在
  • 可以先在有界面的状态测试,再切换headless模式
  • 可以配合Mocha框架一起使用

自动化测试收益

自动化测试的收益 = 迭代次数 全手动执行成本 - 首次自动化成本 - 维护次数 维护成本

哪些地方要测试,需要根据具体项目决定

其他工具:

Selenium

Selenium是一个测试工具集,由Thoughtworks开发,分为两部分。Selenium IDE是一个Firefox浏览器的插件,可以录制用户行为,并快速测试。这个功能挺不错,感兴趣的可以玩一下。

而Selenium WebDriver是一个多语言的驱动浏览器的工具,支持Python、Java、Ruby、Perl、PHP或.Net。并且可以操作IE、Firefox、Safari和Chrome等主流浏览器。通过 ​open​ , ​type​ , ​click​ , ​waitForxxx​ 等指令来模拟用户行为,比如用Java测试:

public void testNew() throws Exception {
    selenium.open("/");
    selenium.type("q", "selenium rc");
    selenium.click("btnG");
    selenium.waitForPageToLoad("30000");
    assertTrue(selenium.isTextPresent("Results * for selenium rc"));
}

PhantomJS

phantomjs利用的是webKit内核,全面支持web而不需浏览器支持,快速,原生支持各种Web标准。 速度快,使用简单。在puppeteer出来之前,大都使用phantom进行前端测试。 相对于puppeteer,其缺点也很明显:

  1. 非亲生,后来自我放弃,不再更新了
  2. 所有操作均需要异步调用,且无法确定操作成功的时机,往往要写很多的setTimeout。没有puppeteer中的async await舒服。

在puppeteer推出之后,就基本不用。

而casperjs是对PhantomJS的一层封装,api更加友好,不再介绍。