Jest入门文档

前端测试 Jest (未完待续)

1 配置环境

  1. node npm install --save-dev jest 需在环境变量中配置
  2. yarn yarn add --dev jest yarn global add jest

2 demo

jest 的工程文件后缀都是xx.test.js,咱们在运行一个jest工程的时候,jest会自动查找运行的后缀为*.test.js的脚本进行单元测试。前端

machers 众多的匹配判断器

  1. toBe() 用于检验基本数据类型的值是否相等
  2. toEqual() 用于检验引用数据类型的值,因为js自己object数据类型的自己特性,引用数据类型对比只是指针的对比,可是须要对比对象的每一个值,因此这时候用到的是toEqual()
  3. Truthiness 布尔值判断的匹配器
  • toBeNull 只匹配 null
  • toBeUndefined 只匹配 undefined
  • toBeDefined 与 toBeUndefined 相反
  • toBeTruthy 匹配任何 if 语句为真
  • toBeFalsy 匹配任何 if 语句为假
  1. 数字匹配器 用于判断数字值之间的对比
  • toBeGreaterThan 大于匹配器
  • toBeGreaterThanOrEqual 大于等于匹配器
  • toBeLessThan 小于匹配器
  • toBeLessThanOrEqual 小于等于匹配器
  • tobe 和 toequal 都是等价功能相同的对于数字
  1. toMatch 字符串匹配器 和字符串的match相同
  2. toContain 数组匹配器 用于判断数组中是否包含某些值
  3. toThrow 报错匹配器 用于测试特定的抛出错误,能够判断报错语句的文字(支持正则匹配),也能够判断报错类型。

异步代码的判断

js 基于单线程异步的特性,在代码中充斥的异步程序和各类回调,因此咱们在测试异步代码的时候要格外注意。一下是各类异步的案例node

  1. callback 回调
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});
 // 这种状况有问题,你们都知道一个ajax请求是一个事件(由两个事务发送和返回组成),当发送成功和返回成功这个事件就是完成的,就是成功的,这个时候jest就认为ajax事件完成了,因此检验会在回调判断执行前结束,没有验证data数据,因此这是有问题的。
复制代码

Jest 提供了相应的方法来done来解决这样的问题,确保回调执行的来完成整个test验证。 使用单个参数调用 done,而不是将测试放在一个空参数的函数。Jest会等done回调函数执行结束后,结束测试。 let's show codeajax

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

  fetchData(callback);
});
  若是 done()永远不会调用,这个测试将失败,这也是你所但愿发生的。
复制代码
  1. Promise 代码使用Promise处理异步程序的话,咱们有更简单的方法进行异步测试。若是Promise返回的状态是reject则测试自动失败。
test('Promise test', ()=>{
        // 断言测试
        expect.assertions(1);
        // 必定记得return,不然测试拿不到promise的状态,测试会在fetchData()完成前完成。
        return fetchData().then(data=>{
            expect(data).tobe('promise')
        })
    })
复制代码

若是指望的promise是reject,咱们能够经过catch来捕获咱们的错误。 请确保添加 expect.assertions 来验证必定数量的断言被调用。 不然一个fulfilled态的 Promise 不会让测试失败。npm

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});
复制代码
  1. .resolves / .rejects 匹配器 Jest有特殊的处理promise的匹配器,resolves和rejects。使用resolves匹配器处理promise,若是返回的状态是reject则测试将自动失败。切记不要丢失return。同理,你用rejects匹配器处理,若是你想获得promise返回是reject可是promise成功了返回一个成功的状态resolve(fulfilled),则测试结果是失败的。
// let's show code~ // resolves test('the data is peanut butter', () => { expect.assertions(1); return expect(fetchData()).resolves.toBe('peanut butter'); }); // rejects test('the fetch fails with an error', () => { expect.assertions(1); return expect(fetchData()).rejects.toMatch('error'); }); 复制代码
  1. Async/Await 你也可使用async/await 处理异步测试。只须要在test的回调函数前面添加async关键字。
// 提早了解async和await的使用方法和场景

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');
  }
});
复制代码

还能够混合使用.resolves / .rejects和Async/Await编程

// 由于await自己返回的就是一个promise。因此咱们能够在返回的promise的基础之上继续测试咱们的代码。
test('the data is peanut butter', async () => {
  expect.assertions(1);
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  await expect(fetchData()).rejects.toMatch('error');
});
复制代码

#Jest的遍历 和 Setup 和 Teardown 进行一些重复的test设置的时候,咱们可使用beforeEach和afterEach。假设咱们在一个交互数据上须要重复的作一些测试设置。假如测试前调用initializeCityDatabase()和测试后调用clearCityDatabase()。那咱们就可使用beforeEach和afterEach了。 let's show code~数组

beforeEach and afterEach

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

beforeEach 和 afterEach处理异步的代码,一样能够采用done和promise,若是initializeCityDatabase()返回的是一个promise咱们能够这样处理他。let's show codepromise

beforeEach(()=>{
        return initializeCityDatabase(); // return一个promise
    })
复制代码

beforeAll and afterAll

Scoping

咱们能够经过Jest的describe函数,经过js函数式编程的思想来建立一个做用域,来模块化咱们的测试。具体场景就是的经过describe来模块咱们的foreach的做用范围。 let's show codebash

// 这里的beforeEach适用于全部的test
beforeEach(() => {
  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', () => {
  // 这里beforeEach仅仅适用于describe中的测试
  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/afterEach和beforeAll/afterAll,那结合descibe来看看咱们的执行顺序。相信你们看完之后会想起js的(任务队列和做用域)。异步

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
    
正如结果查看顺序,全局的会做用到describe内部。 注意执行顺序,beforeALL和afterAll只会执行一次, 全局的beforeEach做用到了describe中的test,还要注意的是after做用域中的after比全局的after先执行。
beforeAll 在beforeEach前先执行,而afterAll在afterEach后执行。
复制代码

若是你想在众多的test中,仅仅想进行其中的一个test,很简单,你只要在他的test语句中添加.only标识就能够了,其余的测试则会跳过了.let's show codeasync

// 只有这个test会跑
test.only('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

// 这个test则会跳过
test('this test will not run', () => {
  expect('A').toBe('A');
});
复制代码
相关文章
相关标签/搜索