开始

安装

运行命令安装Jest

npm install --save-dev jest
# 或
yarn add --dev jest

简单的示例

sum.js

function sum(x, y) {
  return x + y;
}

module.exports = sum;

sum.test.js

const sum = require('../code/sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

在package.json中添加脚本命令

"scripts": {
  "test": "jest"
},

然后运行 npm run test

image-20200927091531591

测试通过,实际结果跟预期结果相同,然后把预期结果修改一下再来看

image-20200927091638269

提示期望值跟实际值不相符。现在已经写完了第一个测试文件

运行单个测试文件是使用jest /path/code.test.js,注意这里斜杠的方向,不能是反斜杠

让Jest支持ES6

Jest只支持CommenJS模块化语法,使用Babel让Jest支持ES6语法

npm install @babel/core @babel/preset-env --save-dev

然后创建babel配置文件.babelrc

{
  "presets": [
    [
      "@babel/preset-env", {
        "targets": {
          "node": "current"
        }
      }
    ]
  ]
}

匹配器

通用匹配器

测试值的最简单方法是完全相等,就像上面的小示例一样。toBe用于测试基础类型完全相等,检查对象的值需要使用toEqual来递归检查每个字段

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

使用not来测试不等于

test('adds 1 + 2 is not 3', () => {
  expect(sum(1, 2)).not.toBe(4);
});

真理

使用真理测试underfinednullfalse

  • toBeNull仅匹配null
  • toBeUndefined仅匹配undefined
  • toBeDefined是相反的toBeUndefined
  • toBeTruthy匹配任何语句视为 true 的语句if
  • toBeFalsy匹配任何语句视为错误的内容if

例如

test('null', () => {
  const n = null;
  expect(n).toBeNull();
});

数字

比较数字的匹配器方法

  • toBeGreaterThan大于
  • toBeGreaterThanOrEqual大于等于
  • toBeLessThan小于
  • toBeLessThanOrEqual小于等于
  • toBe等于
  • toEqual等于
  • toBeCloseTo等于(用于浮点数,比如0.1+0.2)
test('adds 1 + 2', () => {
  expect(sum(1, 2)).toBeGreaterThan(2);
  expect(sum(1, 2)).toBeGreaterThanOrEqual(3);
  expect(sum(1, 2)).toBeLessThan(4);
  expect(sum(1, 2)).toBeLessThanOrEqual(3);
});

字符串

使用toMatch匹配正则表达式

test('match str', () => {
  const str = 'zhangsan@qq.com'
  expect(str).toMatch(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
})

数组

使用toContain来检查数组是否包含特定项

test('array', () => {
  const arr = ['zhangsan', 'lisi', 'wangwu']
  expect(arr).toContain('lisi')
})

异常

使用toThrow来测试函数调用时是否会引发错误

function compileAndroidCode() {
  throw new Error('have error');
}

test('compiling android goes as expected', () => {
  expect(compileAndroidCode).toThrow(Error);
});

更多详细API见官网文档

测试异步代码

有三种当时测试异步代码,回调、promise和等待(async/await)

callback

异步操作如下

function asyncFun(callback) {
  const str = 'test'
  setTimeout(() => {
    callback(str)
  }, 1000)
}

测试代码如下

test('async function', (done) => {
  function callback(data) {
    try {
      expect(data).toBe('test');
      done();
    } catch (error) {
      done(error);
    }
  }
  asyncFun(callback)
})

将测试代码作为回调函数传入被测程序,当异步任务执行完成时调用callback来测试

promise

promise的一部测试较为简单只需要用.then或者.catch来捕获异步返回值即可

// async.js
function asyncFun() {
  return Promise.resolve('test')
}

module.exports = asyncFun;

// async.test.js
test('promise test', () => {
  return asyncFun().then(data => {
    expect(data).toBe('test')
  })
});

promise必须要返回,否则测试将在解析promise之前完成;如果要测试拒绝的结果使用catch代替then

async/await

如同在js代码中使用async/await组合一样,声明函数async,然后赋值时使用await修饰,假设有一个异步任务asyFun返回一个字符串this is a async function,则测试代码可以这样写

test('test asyFun', async () => {
  const data = await asyFun();
  expect(data).toBe('this is a async function');
});

使用预期断言(expect.assertions(number))来验证是否完成了一定数量的异步代码测试

生命周期钩子

  • beforeAll():所有的测试用例执行之前
  • beforeEach():每一个测试用例执行之前
  • afterAll():所有的测试用例执行完成之后
  • afterEach():每一个测试用例执行完成之后

来看具体测试代码,一看就懂

beforeAll(() => {
  console.log('测试开始之前');
})

afterAll(() => {
  console.log('所有的测试用例执行完成');
})

beforeEach(() => {
  console.log('马上开始执行测试用例');
})

afterEach(() => {
  console.log('执行完一个测试用例');
})

test('promise test', () => {
  return asyncFun().then(data => {
    console.log(`测试用例的data:${data}`);
    expect(data).toBe('test')
  })
});

test('promise test not ‘dev’', () => {
  return asyncFun().then(data => {
    console.log(`测试用例的data:${data}`);
    expect(data).not.toBe('dev')
  })
});

运行结果

image-20200927150622677


前端小白