博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习Jest——语法篇
阅读量:4083 次
发布时间:2019-05-25

本文共 6988 字,大约阅读时间需要 23 分钟。

使用匹配器

使用不同匹配器可以测试输入输出的值是否符合预期。下面介绍一些常见的匹配器。

普通匹配器

最简单的测试值的方法就是看是否精确匹配。首先是toBe()

 

test('two plus two is four', () => {  expect(2 + 2).toBe(4);});

toBe用的是JavaScript中的Object.is(),属于ES6中的特性,所以不能检测对象,如果要检测对象的值的话,需要用到toEqual。toEquel递归检查对象或者数组中的每个字段。

 

test('object assignment', () => {  const data = {one: 1};  data['two'] = 2;  expect(data).toEqual({one: 1, two: 2});});

Truthiness

在实际的测试中,我们有时候需要区分undefined、null和false。以下的一些规则有助于我们进行。

  • toBeNull只匹配null
  • toBeUndefined只匹配undefined
  • toBeDefine与toBeUndefined相反
  • toBeTruthy匹配任何if语句为真
  • toBeFalsy匹配任何if语句为假

数字匹配器

大多数的比较数字有等价的匹配器。

  • 大于。toBeGreaterThan()
  • 大于或者等于。toBeGreaterThanOrEqual()
  • 小于。toBeLessThan()
  • 小于或等于。toBeLessThanOrEqual()
  • toBe和toEqual同样适用于数字
    注意:对比两个浮点数是否相等的时候,使用toBeCloseTo而不是toEqual

例子如下:

 

test('two plus two', () => {  const value = 2 + 2;  expect(value).toBeGreaterThan(3);  expect(value).toBeGreaterThanOrEqual(3.5);  expect(value).toBeLessThan(5);  expect(value).toBeLessThanOrEqual(4.5);  // toBe and toEqual are equivalent for numbers  expect(value).toBe(4);  expect(value).toEqual(4);});

 

test('两个浮点数字相加', () => {  const value = 0.1 + 0.2;  //expect(value).toBe(0.3);           这句会报错,因为浮点数有舍入误差  expect(value).toBeCloseTo(0.3); // 这句可以运行});

如果使用toBe就会产生以下结果:

错误

字符串

使用toMatch()测试字符串,传递的参数是正则表达式。

 

test('there is no I in team', () => {  expect('team').not.toMatch(/I/);});test('but there is a "stop" in Christoph', () => {  expect('Christoph').toMatch(/stop/);});

数组

如何检测数组中是否包含特定某一项?可以使用toContain()

 

const shoppingList = [  'diapers',  'kleenex',  'trash bags',  'paper towels',  'beer',];test('购物清单(shopping list)里面有啤酒(beer)', () => {  expect(shoppingList).toContain('beer');});

另外

如果你想在测试特定函数的时候抛出一个错误,在它调用的时候可以使用toThrow。

 

function compileAndroidCode() {  throw new ConfigError('you are using the wrong JDK');}test('compiling android goes as expected', () => {  expect(compileAndroidCode).toThrow();  expect(compileAndroidCode).toThrow(ConfigError);  // You can also use the exact error message or a regexp  expect(compileAndroidCode).toThrow('you are using the wrong JDK');  expect(compileAndroidCode).toThrow(/JDK/);});

测试异步代码

在实际开发过程中,我们经常会遇到一些异步的JavaScript代码。当你有以异步方式运行的代码的时候,Jest需要知道当前它测试的代码是否已经完成,然后它可以转移动另一个测试。也就是说,测试用例一定要在测试对象结束之后才能够结束

为了达到这一目的,Jest有多种方法可以做到。

回调
最常见的异步模式就是回调函数。

注意:回调函数和异步没有必然的联系,回调只是异步的一种调用方式而已,不要将异步和回调两个概念结合起来谈

比如以下代码:

 

// 这里是同步执行的,完全没有异步function fun1(callback) {  callback();}

现在假设一个fetchData(call)函数,获取一些数据并在完成的时候调用call(data),而我想要测试返回的数据是不是字符串'peanut butter'

默认情况下,一旦到达运行上下文底部,jest测试就会立即结束。这意味着这个测试将不能按照预期的进行。

 

function fetchData(call) {  setTimeout(() => {    call('peanut butter1')  },1000);}test('the data is peanut butter', () => {  function callback(data) {    expect(data).toBe('peanut butter'); // 这里没有执行到    // done()  }  fetchData(callback);});

这样做是不会报错的,因为没有执行到我们想要测试的语句中的时候Jest测试已经结束了。(一旦fetchData执行结束,此测试就在没有调用回调函数前结束,因为使用了setTimeout,产生了异步)

而我们可以改成以下:

使用单个参数调用done,而不是将测试放在一个空参数的函数中,Jest会等done回调函数执行结束后,结束测试。

 

function fetchData(call) {  setTimeout(() => {    call('peanut butter1')  },1000);}test('the data is peanut butter', (done) => {  function callback(data) {    expect(data).toBe('peanut butter');    done()  }  fetchData(callback);});

可行

如果done()永远不会被调用,则说明这个测试将失败,这也正是我们所希望看到的。

Promise

如果我们的代码中使用到了Promises,只需要从你的测试中返回一个Promise,Jest就会等待这个Promise来解决。如果承诺被拒绝,则测试将会自动失败。

举个例子,如果fetchData,使用Promise代替回调的话,返回值是应该解析为一个字符串'peanut butter'的Promise。那么我们可以使用以下方式进行测试代码:

 

test('the data is peanut butter', () => {  expect.assertions(1);  return fetchData().then(data => {    expect(data).toBe('peanut butter');  });});

注意:一定要返回Promise,如果省略了return语句,测试将会在fetchData完成之前完成。

另外一种情况,就是想要Promise被拒绝,我们可以使用.catch方法。另外,要确保添加了expect.assertions来验证一定数量的断言被调用。否则一个fulfilled态的Promise不会让测试失败。

 

test('the fetch fails with an error', () => {  expect.assertions(1);  return fetchData().catch(e => expect(e).toMatch('error'));});

.resolves/.rejects

可以使用./resolves匹配器匹配你的期望的声明(跟Promise类似),如果想要被拒绝,可以使用.rejects

 

test('the data is peanut butter', () => {  expect.assertions(1);  return expect(fetchData()).resolves.toBe('peanut butter');});

 

test('the fetch fails with an error', () => {  expect.assertions(1);  return expect(fetchData()).rejects.toMatch('error');});

Async/Await

若要编写async测试,只要在函数前面使用async关键字传递到test。比如,可以用来测试相同的fetchData()方案

 

test('the data is peanut butter', async () => {  expect.assertions(1);  const data = await fetchData();  expect(data).toBe('peanut butter');});test('the fetch fails with an error', async () => {  expect.assertions(1);  try {    await fetchData();  } catch (e) {    expect(e).toMatch('error');  }});

setup and teardown

写测试的时候,我们经常需要进行测试之前做一些准备工作,和在进行测试后需要进行一些整理工作。Jest提供辅助函数来处理这个问题。

为多次测试重复设置

如果你有一些要为多次测试重复设置的工作,可以使用beforeEach和afterEach。

有这样一个需求,需要我们在每个测试之前调用方法initializeCityDatabase(),在每个测试后,调用方法clearCityDatabase()

 

beforeEach(() => {  initializeCityDatabase();});afterEach(() => {  clearCityDatabase();});test('city database has Vienna', () => {  expect(isCity('Vienna')).toBeTruthy();});test('city database has San Juan', () => {  expect(isCity('San Juan')).toBeTruthy();});

一次性设置

在某些情况下,你只需要在文件的开头做一次设置。这种设置是异步行为的时候,你不太可能一行处理它。Jest提供了beforeAll和afterAll处理这种情况。

 

beforeAll(() => {  return initializeCityDatabase();});afterAll(() => {  return clearCityDatabase();});test('city database has Vienna', () => {  expect(isCity('Vienna')).toBeTruthy();});test('city database has San Juan', () => {  expect(isCity('San Juan')).toBeTruthy();});

作用域

默认情况下,before和after的块可以应用到文件中的每一个测试。此外可以通过describe块来将将测试中的某一块进行分组。当before和after的块在describe块内部的时候,则只适用于该describe块内的测试。

比如说,我们不仅有一个城市的数据库,还有一个食品数据库。我们可以为不同的测试做不同的设置︰

 

// Applies to all tests in this filebeforeEach(() => {  return initializeCityDatabase();});test('city database has Vienna', () => {  expect(isCity('Vienna')).toBeTruthy();});test('city database has San Juan', () => {  expect(isCity('San Juan')).toBeTruthy();});describe('matching cities to foods', () => {  // Applies only to tests in this describe block  beforeEach(() => {    return initializeFoodDatabase();  });  test('Vienna <3 sausage', () => {    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);  });  test('San Juan <3 plantains', () => {    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);  });});

注意:顶级的beforeEach描述块内的beforeEach之前执行,以下的例子可以方便我们认识到执行的顺序

 

beforeAll(() => console.log('1 - beforeAll'));afterAll(() => console.log('1 - afterAll'));beforeEach(() => console.log('1 - beforeEach'));afterEach(() => console.log('1 - afterEach'));test('', () => console.log('1 - test'));describe('Scoped / Nested block', () => {  beforeAll(() => console.log('2 - beforeAll'));  afterAll(() => console.log('2 - afterAll'));  beforeEach(() => console.log('2 - beforeEach'));  afterEach(() => console.log('2 - afterEach'));  test('', () => console.log('2 - test'));});// 1 - beforeAll// 1 - beforeEach// 1 - test// 1 - afterEach// 2 - beforeAll// 1 - beforeEach  //特别注意// 2 - beforeEach// 2 - test// 2 - afterEach// 1 - afterEach// 2 - afterAll// 1 - afterAll

作者:GpingFeng
链接:https://www.jianshu.com/p/e54218d67628
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
serial也是见到很多次了,似乎它就是一种串行通信协议
查看>>
TBUS的一些信息
查看>>
PX4+激光雷达在gazebo中仿真实现(古月居)
查看>>
专业和业余的区别就在于你在基础在基本功打磨练习花的时间
查看>>
通过mavlink实现自主航线的过程笔记
查看>>
Ardupilot飞控Mavlink代码学习
查看>>
这些网站有一些嵌入式面试题合集
查看>>
我觉得刷题是有必要的,不然小心实际被问的时候懵逼,我觉得你需要刷个50份面试题。跟考研数学疯狂刷卷子一样!
查看>>
我觉得嵌入式面试三要素:基础吃透+项目+大量刷题,缺一不可。不刷题是不行的。而且得是大量刷,刷出感觉套路,别人做题都做得是固定题型套路条件反射了,你还在那慢慢理解慢慢推是不行的,也是考研的教训。
查看>>
相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
查看>>
现在来看,做个普罗米修斯的docker镜像对我而言并不难,对PX4仿真环境配置也熟悉了。
查看>>
删除docker容器和镜像的命令
查看>>
VINS-Fusion Intel® RealSense™ Depth Camera D435i
查看>>
使用Realsense D435i运行VINS-Fusion并建图
查看>>
gazebo似乎就是在装ROS的时候一起装了,装ROS的时候选择的是ros-melodic-desktop-full的话。
查看>>
React + TypeScript 实现泛型组件
查看>>
TypeScript 完全手册
查看>>
React Native之原理浅析
查看>>
Git操作清单
查看>>
基础算法
查看>>