jest_note

作者: glAkihi | 来源:发表于2019-01-12 15:07 被阅读0次

    方法

    expect

    toBe()

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

    toEquel()

    • 要检测对象的值的话,需要用到toEqual。toEquel递归检查对象或者数组中的每个字段。

    Other

    • 在实际的测试中,我们有时候需要区分undefined、null和false。以下的一些规则有助于我们进行。
      • toBeNull只匹配null
      • toBeUndefined只匹配undefined
      • toBeDefine与toBeUndefined相反
      • toBeTruthy匹配任何if语句为真
      • toBeFalsy匹配任何if语句为假

    数字匹配器

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

    • 大于。toBeGreaterThan()
    • 大于或者等于。toBeGreaterThanOrEqual()
    • 小于。toBeLessThan()
    • 小于或等于。toBeLessThanOrEqual()
    • toBe和toEqual同样适用于数字

    注意:对比两个浮点数是否相等的时候,使用toBeCloseTo而不是toEqual

    字符串

    使用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');
    });
    

    测试异步代码

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

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

    Promise

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

    注意:一定要返回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

    为多次测试重复设置

    如果你有一些要为多次测试重复设置的工作,可以使用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 file
    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', () => {
      // 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
    

    Mock Function

    Jest中有两种方式的Mock Function,一种是利用Jest提供的Mock Function创建,另外一种是手动创建来覆写本身的依赖实现。

    假设我们要测试函数 forEach 的内部实现,这个函数为传入的数组中的每个元素调用一个回调函数,代码如下:

    function forEach(items, callback) {
      for (let index = 0; index < items.length; index++) {
        callback(items[index]);
      }
    }
    

    为了测试此函数,我们可以使用一个 mock 函数,然后检查 mock 函数的状态来确保回调函数如期调用。

    const mockCallback = jest.fn();
    forEach([0, 1], mockCallback);
    
    // 此模拟函数被调用了两次
    expect(mockCallback.mock.calls.length).toBe(2);
    
    // 第一次调用函数时的第一个参数是 0
    expect(mockCallback.mock.calls[0][0]).toBe(0);
    
    // 第二次调用函数时的第一个参数是 1
    expect(mockCallback.mock.calls[1][0]).toBe(1);
    

    几乎所有的Mock Function都带有 .mock的属性,它保存了此函数被调用的信息。 .mock 属性还追踪每次调用时 this的值,所以也让检视 this 的值成为可能:

    const myMock = jest.fn();
    
    const a = new myMock();
    const b = {};
    const bound = myMock.bind(b);
    bound();
    
    console.log(myMock.mock.instances);
    

    在测试中,需要对函数如何被调用,或者实例化做断言时,这些 mock 成员变量很有帮助意义︰

    // 这个函数只调用一次
    expect(someMockFunction.mock.calls.length).toBe(1);
    
    // 这个函数被第一次调用时的第一个 arg 是 'first arg'
    expect(someMockFunction.mock.calls[0][0]).toBe('first arg');
    
    // 这个函数被第一次调用时的第二个 arg 是 'second arg'
    expect(someMockFunction.mock.calls[0][1]).toBe('second arg');
    
    // 这个函数被实例化两次
    expect(someMockFunction.mock.instances.length).toBe(2);
    
    // 这个函数被第一次实例化返回的对象中,有一个 name 属性,且被设置为了 'test’ 
    expect(someMockFunction.mock.instances[0].name).toEqual('test');
    

    Mock 函数也可以用于在测试期间将测试值注入您的代码︰

    const myMock = jest.fn();
    console.log(myMock());
    // > undefined
    
    myMock
      .mockReturnValueOnce(10)
      .mockReturnValueOnce('x')
      .mockReturnValue(true);
    
    console.log(myMock(), myMock(), myMock(), myMock());
    

    大多数现实世界的例子实际上都涉及到将一个被依赖的组件上使用 mock 函数替代并进行配置,这在技术上(和上面的描述)是相同的。 在这些情况下,尽量避免在非真正想要进行测试的任何函数内实现逻辑。

    有些情况下超越指定返回值的功能是有用的,并且全面替换了模拟函数的实现。

    const myMockFn = jest.fn(cb => cb(null, true));
    
    myMockFn((err, val) => console.log(val));
    // > true
    
    myMockFn((err, val) => console.log(val));
    // > true
    

    如果你需要定义一个模拟的函数,它从另一个模块中创建的默认实现,mockImplementation方法非常有用

    // foo.js
    module.exports = function() {
      // some implementation;
    };
    
    // test.js
    jest.mock('../foo'); // this happens automatically with automocking
    const foo = require('../foo');
    
    // foo is a mock function
    foo.mockImplementation(() => 42);
    foo();
    // > 42
    

    当你需要重新创建复杂行为的模拟功能,这样多个函数调用产生不同的结果时,请使用 mockImplementationOnce 方法︰

    const myMockFn = jest
      .fn()
      .mockImplementationOnce(cb => cb(null, true))
      .mockImplementationOnce(cb => cb(null, false));
    
    myMockFn((err, val) => console.log(val));
    // > true
    
    myMockFn((err, val) => console.log(val));
    // > false
    

    当指定的mockImplementationOnce 执行完成之后将会执行默认的被jest.fn定义的默认实现,前提是它已经被定义过。

    const myMockFn = jest
      .fn(() => 'default')
      .mockImplementationOnce(() => 'first call')
      .mockImplementationOnce(() => 'second call');
    
    console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
    // > 'first call', 'second call', 'default', 'default'
    

    对于有通常链接的方法(因此总是需要返回this)的情况,我们有一个语法糖的API以.mockReturnThis()函数的形式来简化它,它也位于所有模拟器上:

    const myObj = {
      myMethod: jest.fn().mockReturnThis(),
    };
    
    // is the same as
    
    const otherObj = {
      myMethod: jest.fn(function() {
        return this;
      }),
    };
    

    相关文章

      网友评论

          本文标题:jest_note

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