关于前端:day34-测试二功能性测试

37次阅读

共计 4570 个字符,预计需要花费 12 分钟才能阅读完成。

测试工具比照

比拟风行的框架:Mocha、Jest 和 Jasmine
这三个工具都基于断言函数(assertion functions)来帮忙咱们减少测试的可读性和可扩展性,也都反对咱们理解测试进度和生成最终的测试后果报告,理解代码的覆盖率。

最小化的单元测试

首先咱们要装置 Jest,这要基于 Node 和 NPM,你能够在 Terminal 通过运行上面的命令来看是否曾经装置了 Node 和 NPM。如果返回的是相干的版本信息,那么证实这两个工具曾经存在了。
`node -v
npm -v`
下一步,咱们须要再装置 Jest,在 Terminal,咱们能够通过上面这行命令装置 Jest。global 的 flag 能够容许咱们从命令行的客户端如 Terminal 或 Command Prompt 间接运行 Jest 测试。
npm install jest --global
上面,假如咱们想要写一个斐波那契数列函数,依照测试驱动的思维,咱们先来创立一个 fib.test.js 的测试文件,外面蕴含如下的测试用例:如果咱们输出 7,斐波那契数列后果应该是 13。

test('7 的斐波那契后果是 13', () => {expect(fib(7, 0, 1)).toBe(13);
});

通过上面的指令,咱们能够运行下面的测试脚本:
jest fib.test.js
这时,咱们如果运行上述的测试,后果必定是报错。因为在这个时候,咱们还没创立斐波那契数列的函数!所以这一步就是咱们红绿重构中的红色局部。
这时,咱们晓得为了通过测试,下一步须要创立一个斐波那契的函数。
咱们能够通过如下的形式创立一个并且保留在 fib.js 里。在这个文件的尾部,咱们做了模块化的导出,为的是让咱们可能在方才创立的测试文件中做导入和援用。

function fib(n, lastlast, last){if (n == 0) {return lastlast;}
  if (n == 1) {return last;}
  return fib(n-1, last, lastlast + last);
}

module.exports = fib;

之后,咱们能够在后面的用例中导入斐波那契函数。

var fib = require('./fib');

test('7 的斐波那契后果是 13', () => {expect(fib(7, 0, 1)).toBe(13);
});

当咱们再次通过之前的指令运行下面的文件时,就能够看到通过的后果。也就是到了红绿重构中的绿色。因为这是一个绝对较为简单的测试,咱们不须要重构,所以当执行到这里时,咱们就能够当做测试实现了。

数据值类型的匹配

在数据类型的一讲中,咱们讲过了 JavaScript 赋值中的一些常见的坑,比方值的比拟和严格比拟所返回的后果是不同的,以及除了布尔值之外,可能会返回否值的数据类型。所以在测试的时候,咱们也应该留神咱们期待的后果和理论后果是不是匹配的。Jest 就自带了很多的内置办法来帮忙咱们做数据类型的匹配。
上面咱们能够通过两个例子来看看。
在第一个例子中,咱们能够看到当咱们应用 toEqual 来做比拟的时候,undefined 就被忽略了,所以测试能够通过,但当咱们应用 toStrictEqual 的时候,则能够看到严格比拟的后果,测试的后果就是失败。在第二个例子中,咱们能够看到因为数字的值能够是 NaN,它是 falsy 的值,所以测试的后果是通过。

// 例子 1
test('check equal', () => {var obj = { a: undefined, b: 2}
  expect(obj).toEqual({b: 2});
});

test('check strict equal', () => {var obj = { a: undefined, b: 2}
  expect(obj).toStrictEqual({b: 2});
});

// 例子 2
test('check falsy', () => {
  var num = NaN;
  expect(num).toBeFalsy();});

咱们在后面一个大节斐波那契的例子中用到的 toBe(),是代表比拟还是严格比拟的后果呢?实际上都不是,toBe() 用的是 Object.is。除了 toBeFasly,其它的测试真值的办法还有 toBeNull()、toBeUndefined()、toBeDefined()、toBeTruthy()。同样,在应用的时候,肯定要留神它们的实际意义。
除了严格比拟和否值外,另外一个也是咱们在数据类型讲到的问题,就是数字中的浮点数丢精问题。针对这个问题,咱们也能够看到当咱们用 0.1 加 0.2 的时候,咱们晓得它不是等于 0.3,而是等于 0.30000000000000004(0.3+4×10−17)。所以 expect(0.1+0.2).toBe(0.3) 的后果是失败的,而如果咱们应用 toBeCloseTo() 的话,则能够看到靠近的后果是能够通过测试的。
除了比照靠近的数字外,Jest 还有 toBeGreaterThan()、toBeGreaterThanOrEqual(),toBeLessThan() 和 toBeLessThanOrEqual() 等帮忙咱们比照大于、大于等于、小于、小于等于的办法,便于咱们对数值进行比拟。

test('浮点数相加', () => {
  var value = 0.1 + 0.2;
  expect(value).toBe(0.3);        // 失败
});

test('浮点数相加', () => {
  var value = 0.1 + 0.2;
  expect(value).toBeCloseTo(0.3); // 通过
});

说完了数字,咱们再来看看字符串和数组。在上面的两个例子中,咱们能够通过 toMatch() 用正则表达式在字符串中测试一个词是否存在。相似的,咱们能够通过 toContain() 来看一个元素是否在一个数组当中。

test('单词里有 love', () => {expect('I love animals').toMatch(/love/);
});

test('单词里没有 hate', () => {expect('I love peace and no war').not.toMatch(/hate/);
});

var nameList = ['Lucy', 'Jessie'];
test('Jessie 是否在名单里', () => {expect(nameList).toContain('Jessie');
});

嵌套构造的测试

上面,咱们再来看看嵌套构造的测试。咱们能够把一组测试通过 describe 嵌套在一起。比方咱们有一个长方形的类,测试过程能够通过如下的形式嵌套。里面一层,咱们形容的是长方形的类;两头一层是长方形面积的计算;内层测试蕴含了长和宽的设置。除了嵌套构造,咱们也能够通过 beforeEach 和 afterEach 来设置在每组测试前后的前置和后置工作。

describe('Rectangle class', ()=> {describe('area is calculated when', ()=> {test('sets the width', ()=> {...});
    test('sets the height', ()=> {...});
  });
});

响应式异步测试

咱们说前端的测试很多是事件驱动的,之前咱们在讲异步编程的时候,也说到前端开发离不开异步事件。那么通常测试工具也会对异步调用的测试有相干的反对。
还是以 Jest 为例,就反对了 callback、promise/then 和咱们说过的 async/await。上面,就让咱们针对每一种模式具体来看看。
callback

test('数据是:价格为 21', done => {function callback(error, data) {if (error) {done(error);
      return;
    }
    try {expect(data).toBe({price:21});
      done();} catch (error) {done(error);
    }
  }
  fetchData(callback);
});

promise/then 以及 async/await

// 例子 1:promise then
test('数据是:价格为 21', () => {return fetchData().then(data => {expect(data).toBe({price:21});
  });
});

// 例子 2:async await
test('数据是:价格为 21', async () => {var data = await fetchData();
  expect(data).toBe({price:21});
});

Mock 和 Stub

测试 Mock 和 Stub 都是采纳替换的形式来实现被测试的函数中的依赖关系。它们的区别是 Stub 是手动代替实现的接口,而 Mock 采纳的则是函数代替的形式。
Mock 能够帮忙咱们模仿带返回值的性能,比方上面的 myMock,能够在一系列的调用中,模仿返回后果。

var myMock = jest.fn();
console.log(myMock()); // 返回 undefined

myMock.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);

console.log(myMock(), myMock(), myMock(), myMock()); // 返回 10, 'x', true, true

在这里,Jest 应用了咱们后面在函数式编程中讲过的间断传递款式(CPS),这样做的益处是能够帮忙咱们尽量避免应用 Stub。
Stub 的实现会有很多手动的工作,而且因为它并不是最终的实在接口,所以手工实现实在接口的简单逻辑不仅不能保障和理论接口的一致性,还会造成很多额定的开发成本。而应用基于 CPS 的 Mock,能够取代 Stub,并且节俭模仿过程中的工作量。

var filterTestFn = jest.fn();

// 首次返回 `true`;之后返回 `false` 
filterTestFn.mockReturnValueOnce(true).mockReturnValueOnce(false);

var result = [11, 12].filter(num => filterTestFn(num));

console.log(result); // 返回 [11]
console.log(filterTestFn.mock.calls[0][0]); // 返回 11
console.log(filterTestFn.mock.calls[1][0]); // 返回 12

UI 自动化测试
无头浏览器和自动化测试

npm install --save-dev jest-puppeteer
{"preset": "jest-puppeteer"}
describe('极客工夫', () => {beforeAll(async () => {await page.goto('https://time.geekbang.org/');
  });

  it('题目应该是" 极客工夫 - 轻松学习,高效学习 - 极客邦 "', async () => {await expect(page.title()).resolves.toMatch('Google');
  });
});

此文章为 2 月 Day12 学习笔记,内容来源于极客工夫《Jvascript 进阶实战课》,大家共同进步💪💪

正文完
 0