美文网首页
jest使用

jest使用

作者: 热心市民在线搬砖 | 来源:发表于2019-12-06 16:23 被阅读0次

    一、起步 #

    1、挂载

    // 方法一
    const Constructor = Vue.extend(monitor);
    const vm = new Constructor();
    // 方法二
    const monitor = mount(monitor, { // 现在挂载组件,你便得到了这个包裹器
         mocks: { //模拟数据
             $store
         }
     });
    const vm = monitor.vm;
    

    2、生成jest.config.js配置文件

    • 安装相关依赖
    npm install jest --global
    jest --init
    // 安装babel相关
    npm install --save-dev babel-jest @babel/core @babel/preset-env
    
    • babel配置
    // babel.config.js
    module.exports = {
      presets: [
        ['@babel/preset-env', {targets: {node: 'current'}}],
      ],
    };
    
    • jest通过babel支持ts
    npm install --save-dev @babel/preset-typescript
    // 并在babel.config.js中添加
    presets: [
      ...
      '@babel/preset-typescript',
      ...
      ],
    
    • 由于Babel对TypeScript的支持是编译,但是Jest在运行测试时不会进行类型检查。如果需要,可以使用ts-jest

    二、常用匹配器 #

    • expect(完整列表)
    • 在此代码中,expect (2 + 2)返回一个"期望"的对象。 你通常不会对这些期望对象调用过多的匹配器。 在此代码中,.toBe(4)是匹配器。 当 Jest 运行时,它会跟踪所有失败的匹配器,以便它可以为你打印出很好的错误消息。
    test('two plus two is four', () => {
      expect(2 + 2).toBe(4);
    });
    
    • toBe用来测试精确相等,如果想要检查对象的值,使用toEqual代替,toEqual递归检查对象或数组的每个字段
    • 匹配相反的测试值
    expect(a + b).not.toBe(0);
    
    • Truthiness:在测试中,你有时需要区分 undefined、 null,和 false,但有时你又不需要区分。 Jest 让你明确你想要什么。
      • toBeNull 只匹配 null
      • toBeUndefined 只匹配 undefined
      • toBeDefined 与 toBeUndefined 相反
      • toBeTruthy 匹配任何 if 语句为真
      • toBeFalsy 匹配任何 if 语句为假
      test('null', () => {
        const n = null;
        expect(n).toBeNull();
        expect(n).toBeDefined();
        expect(n).not.toBeUndefined();
        expect(n).not.toBeTruthy();
        expect(n).toBeFalsy();
      });
      test('zero', () => {
        const z = 0;
        expect(z).not.toBeNull();
        expect(z).toBeDefined();
        expect(z).not.toBeUndefined();
        expect(z).not.toBeTruthy();
        expect(z).toBeFalsy();
      });
      
    • 数字
    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);
    });
    // 对于浮点数相比较,使用toBeCloseTo而不是toEqual
    test('两个浮点数字相加', () => {
      const value = 0.1 + 0.2;
      //expect(value).toBe(0.3);   这句会报错,因为浮点数有舍入误差
      expect(value).toBeCloseTo(0.3); // 这句可以运行
    });
    
    • 字符串
    // 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('the shopping list has beer on it', () => {
      expect(shoppingList).toContain('beer');
      expect(new Set(shoppingList)).toContain('beer');
    });
    
    • 例外情况
      测试某个特定函数在调用时抛出错误,使用toThrow
    function compileAndroidCode() {
      throw new Error('you are using the wrong JDK');
    }
    
    test('compiling android goes as expected', () => {
      expect(compileAndroidCode).toThrow();
      expect(compileAndroidCode).toThrow(Error);
    
      // 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有若干方法处理这种情况。

    • 回调
      最常见的异步模式是回调函数。
      例如,假设您有一个fetchData(callback)函数,获取一些数据并在完成时调用callback(data)。你想要测试此返回的数据是否为字符串'peanut butter'.
      默认情况下,Jest 测试一旦执行到末尾就会完成。 那意味着该测试将不会按预期工作:
    // 不要这样做!
    test('the data is peanut butter', () => {
      function callback(data) {
        expect(data).toBe('peanut butter');
      }
    
      fetchData(callback);
    });
    

    问题在于一旦fetchData执行结束,此测试就在没有调用回调函数前结束。
    还有另一种形式的test,解决此问题。 使用单个参数调用 done,而不是将测试放在一个空参数的函数。 Jest会等done回调函数执行结束后,结束测试。

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

    如果 done()永远不会调用,这个测试将失败,这也是你所希望发生的。

    • Promises
      如果你的代码使用Promise,则有一种更简单的方法来处理异步测试。从测试中返回一个承诺,Jest将等待该承诺解决。如果承诺被拒绝,则测试将自动失败。
      举个例子,如果fetchData不使用回调函数,而是返回一个 Promise,其解析值为字符串'peanut butter'我们可以这样测试:
    // 测试异步调用
    function fetchData(resolve, reject) {
      setTimeout(() => {
        return resolve("peanut butter");
      }, 2000);
    }
    let fetch1 = new Promise(fetchData);
    test('the data is peanut butter', () => {
      return fetch1.then(data => {
        expect(data).toBe('peanut butter');
      });
    });
    
    • .resolves / .rejects
      您也可以在 expect 语句中使用.resolves匹配器,Jest 将等待此 Promise 解决。 如果承诺被拒绝,则测试将自动失败。
    test('the data is peanut butter', () => {
      return expect(fetchData()).resolves.toBe('peanut butter');
    });
    

    一定不要忘记把整个断言作为返回值返回⸺如果你忘了return语句的话,在 fetchData 返回的这个 promise 变更为 resolved 状态、then() 有机会执行之前,测试就已经被视为已经完成了。

    如果你想要 Promise 被拒绝,使用 .catch 方法。 它参照工程 .resolves 匹配器。 如果 Promise 被拒绝,则测试将自动失败。

    test('the fetch fails with an error', () => {
      return expect(fetchData()).rejects.toMatch('error');
    });
    
    • Async/Await
      可以在测试中使用 async 和 await,要编写异步测试,请在传递给测试的函数前面使用async关键字
    test('the data is peanut butter', async () => {
      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');
      }
    });
    

    同样,可以将async和await与.resolves或.rejects结合使用。

    test('the data is peanut butter', async () => {
      await expect(fetchData()).resolves.toBe('peanut butter');
    });
    
    test('the fetch fails with an error', async () => {
      await expect(fetchData()).rejects.toThrow('error');
    });
    

    在这些情况下,async和await实际上是语法糖,与应诺示例使用的逻辑相同。
    上述的诸多形式中没有哪个形式特别优于其他形式,你可以在整个代码库中,甚至也可以在单个文件中混合使用它们。 这只取决于哪种形式更能使您的测试变得简单。

    三、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();
    });
    

    beforeEach和afterEach能够通过与 异步代码测试 相同的方式处理异步代码 — — 他们可以采取 done 参数或返回一个 promise。 例如,如果 initializeCityDatabase() 返回解决数据库初始化时的 promise ,我们会想返回这一 promise︰

    beforeEach(() => {
      return initializeCityDatabase();
    });
    
    • 一次性设置
      在某些情况下,你只需要在文件的开头做一次设置。当设置异步时,这尤其麻烦,因此您不能内联. Jest 提供beforeAllafterAll处理这种情况。
      例如,如果initializeCityDatabaseclearCityDatabase都返回了 promise ,城市数据库可以在测试中重用,我们就能把我们的测试代码改成这样:
    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 块内的测试
      注意,顶级的 beforeEach 在 describe 块级的 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
    
    • desribe和test块的执行顺序
      Jest 会在所有真正的测试开始之前执行测试文件里所有的describe处理程序(handlers)。 这是在before*after*处理程序里面 (而不是在 describe 块中)进行准备工作和整理工作的另一个原因。 当 describe 块运行完后,,默认情况下,Jest 会按照 test 出现的顺序(译者注:原文是in the order they were encountered in the collection phase)依次运行所有测试,,等待每一个测试完成并整理好,然后才继续往下走
    • 通用建议
      如果测试失败,第一件要检查的事就是,当仅运行这条测试时,它是否仍然失败。要仅使用Jest运行一个测试,请将该test命令临时更改为test.only
    test.only('this will be the only test that runs', () => {
      expect(true).toBe(false);
    });
    
    test('this test will not run', () => {
      expect('A').toBe('A');
    });
    

    如果你有一个测试,当它作为一个更大的用例中的一部分时,经常运行失败,但是当你单独运行它时,并不会失败,所以最好考虑其他测试对这个测试的影响。 通常可以通过修改 beforeEach 来清除一些共享的状态来修复这种问题。如果不确定是否正在修改某些共享状态,也可以尝试使用beforeEach记录数据。

    相关文章

      网友评论

          本文标题:jest使用

          本文链接:https://www.haomeiwen.com/subject/xhvsgctx.html