Jest单元测试(二)

Jest 使用匹配器

新建 using-matchers.test.js 测试文件

  1. 普通匹配 - toEqual
// using-matchers.test.js

// toBe 使用 Object.is 来测试精确相等
test('two plus two is four', () => {
    expect(2 + 2).toBe(4);
});

// 如果您想要检查对象的值,请使用 toEqual, toEqual 递归检查对象或数组的每个字段。
test('object assignment', () => {
    const data = {one: 1};
    data['two'] = 2;
    expect(data).toEqual({one: 1, two: 2});
});

// not 可以测试相反的匹配︰
test('adding positive numbers is not zero', () => {
    for (let a = 1; a < 10; a++) {
      for (let b = 1; b < 10; b++) {
        expect(a + b).not.toBe(0);
      }
    }
});

  1. Truthiness 匹配

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();
  });
  1. 数字匹配 - toBe
// 大多数的比较数字有等价的匹配器。
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); // 这句可以运行
});


  1. 字符串匹配 - toMatch

您可以检查对具有 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/);
});
  1. 数组匹配 - toContain
    可以通过 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');
});

Jest 挂载与卸载函数


// 在所有测试开始之前调用(调用一次)
beforeAll(() => {
  console.log('beforeAll init data ')
});
  
// 在所有测试用例执行完之后调用(一次)
afterAll(() => {
  console.log('afterAll init data ')
});

// 在每个测试用例执行之前调用
beforeEach(() => {
  console.log('beforeEach init data ')
});
// 在每个测试用来执行完之后调用  
afterEach(() => {
  console.log('afterEach clear data ')
});

test('test 1', () => {

});
test('test 2', () => {

});

Jest 测试分组

使用 describe 函数 给测试用例进行分组

describe('普通配置器的案例组', () => {
    // toBe 使用 Object.is 来测试精确相等
    test('two plus two is four', () => {
        expect(2 + 2).toBe(4);
    });
    // 如果您想要检查对象的值,请使用 toEqual, toEqual 递归检查对象或数组的每个字段。
    test('object assignment', () => {
        const data = {one: 1};
        data['two'] = 2;
        expect(data).toEqual({one: 1, two: 2});
    });
    // ....
});

describe('Truthiness匹配器的案例组', () => {
    test('null', () => {
        const n = null;
        expect(n).toBeNull();
        expect(n).toBeDefined();
        expect(n).not.toBeUndefined();
        expect(n).not.toBeTruthy();
        expect(n).toBeFalsy();
    });
    // ...
});

Jest 作用域

// Applies to all tests in this file
beforeEach(() => {
  console.log('在 下面所有的测试用例之前 执行')
});

// toBe 使用 Object.is 来测试精确相等
test('1.two plus two is four', () => {
    expect(2 + 2).toBe(4);
});

// 如果您想要检查对象的值,请使用 toEqual, toEqual 递归检查对象或数组的每个字段。
test('2.object assignment', () => {
    const data = {one: 1};
    data['two'] = 2;
    expect(data).toEqual({one: 1, two: 2});
});
  
describe('Truthiness匹配器的案例组', () => {
  // Applies only to tests in this describe block
  beforeEach(() => {
    console.log('仅仅在 下面这一个测试用例之前 会执行')
  });
  test('3.null', () => {
      const n = null;
      expect(n).toBeNull();
      expect(n).toBeDefined();
  });
});

Jest 模拟函数

编写utils.js

const checkedLogin = (name, password) => {
    if(name === 'admin' && password === '123456'){
      return true
    } else {
      return false
    }
} 
// export default { checkedLogin } // es6 ok
module.exports= {
  checkedLogin
}

编写mock-func.js

import utils from './utils.js'


export const login =(name, password, callback) => {
    if(utils.checkedLogin(name, password)){
      callback('登录成功'); // 编写测试模拟该函数被调用
    } else {
      callback('登录失败'); // 编写测试模拟该函数被调用
    }
}

在 mock-func.test.js 编写单元测试(模拟回调函数如何被调用、调用时的参数和返回值的信息等)


import { login } from './mock-func.js'

describe('login 测试组', () => {

    test('test login1 函数有返回结果', ()=> {
      // 1.模拟登录的回掉函数
      // const mockCallback = jest.fn(res => { // callback 函数接收到的参数
      //     return '登录返回的结果:' + res // callback 函数返回的结果
      // });
      const mockCallback = jest.fn()
        .mockImplementation(res => { // callback 函数接收到的参数
            return '登录返回的结果:' + res // callback 函数返回的结果
        });

      // 2.调用登录函数 
      login('admin', 1234, mockCallback)

      // 3.判断 callback 函数被调用的次数
      expect(mockCallback.mock.calls.length).toBe(1);
      // 4.判断 callback 函数接收到的参数
      expect(mockCallback.mock.calls[0]).toContain('登录失败'); //  ["登录失败"]
      // 5.判断 callback 函数返回的结果
      expect(mockCallback.mock.results[0].value).toBe('登录返回的结果:登录失败');
      // 6.判断 callback 是否被调用
      expect(mockCallback).toHaveBeenCalled();
      // 7.判断 callback 调用时传入的参数是:登录失败
      expect(mockCallback).toHaveBeenCalledWith('登录失败');
    })

    // mock 没有返回值    
    test('test login2 函数没有返回结果', ()=> {
      // 1.模拟登录的回掉函数
      const mockCallback = jest.fn(); // 函数没有返回直接

      // 2.调用登录函数 
      login('admin', 1234, mockCallback)

      // 3.判断 callback 函数被调用的次数
      expect(mockCallback.mock.calls.length).toBe(1);
      // 4.判断 callback 函数接收到的参数
      expect(mockCallback.mock.calls[0]).toContain('登录失败'); //  ["登录失败"]
      // 5.判断 callback 函数没有返回结果
      expect(mockCallback.mock.results[0].value).toBeUndefined()
    })

    // mock 返回值
    test('test login3 自定义函数的返回结果', ()=> {
        // 1.模拟登录的回掉函数
        const mockCallback = jest.fn()
        mockCallback.mockReturnValueOnce('自定义函数的返回结果') // 函数只返回一次
        // mockCallback.mockReturnValue('自定义函数的返回结果') // 函数可被调用多次,返回多次
        
        // 2.调用登录函数 
        login('admin', 1234, mockCallback)
  
        // 3.判断 callback 函数被调用的次数
        expect(mockCallback.mock.calls.length).toBe(1);
        // 4.判断 callback 函数接收到的参数
        expect(mockCallback.mock.calls[0]).toContain('登录失败'); //  ["登录失败"]
        // 5.判断 callback 函数返回的结果
        expect(mockCallback.mock.results[0].value).toBe('自定义函数的返回结果');
    })

})

所有的 mock 函数都有这个特殊的 .mock属性,它保存了关于此函数如何被调用、调用时的返回值的信息。 .mock 属性还追踪每次调用时 this的值,

执行单元测试:yarn test

LiuJun-MacBook-Pro:jest liujun$ yarn test mock-func.js
yarn run v1.13.0
$ jest mock-fu
 PASS  ./mock-func.test.js
  login 测试组
    ✓ test login1 函数有返回结果 (4 ms)
    ✓ test login2 函数没有返回结果
    ✓ test login3 自定义函数的返回结果

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.832 s, estimated 2 s
Ran all test suites matching /mock-fu/i.
✨  Done in 3.59s.
LiuJun-MacBook-Pro:jest liujun$ 

在 mock-func.test.js 编写单元测试(模拟 utils 模块,模拟 utils.checkedLogin 函数的实现 )



import { login } from './mock-func.js'

// 1.jest.mock('./utils.js')
let utils = require('./utils.js') // import utils from './utils.js' // ok
// 2.mock 掉 ./utils.js 所有的函数
jest.mock('./utils.js') // 这两个导入顺序没有要求,但是不用再组里面导入

describe('login 测试组', () => {
    // mock 模拟utils模块
    test('test login4 模拟内部的函数(模块)', ()=> {
        // 3.重新实现utils模块对应的函数
        // utils.checkedLogin.mockResolvedValue(true) // ok
        utils.checkedLogin.mockImplementation((name, passwrod )=> {
            if(name === 'admin' && passwrod === '1234'){
                return true
            } else {
                return false
            }
        })

        // 4.模拟登录的回掉函数
        const mockCallback = jest.fn()
        mockCallback.mockReturnValueOnce('自定义函数的返回结果') // 函数只返回一次
        
        // 5.调用登录函数 
        login('admin', '1234', mockCallback)
  
        // 6.判断 callback 函数被调用的次数
        expect(mockCallback.mock.calls.length).toBe(1);
        // 7.判断 callback 函数接收到的参数
        expect(mockCallback.mock.calls[0]).toContain('登录成功'); //  ["登录失败"]
        // 5.判断 callback 函数返回的结果
        expect(mockCallback.mock.results[0].value).toBe('自定义函数的返回结果');
    })

})

执行单元测试:yarn test

LiuJun-MacBook-Pro:jest liujun$ yarn test mock-func.js
yarn run v1.13.0
$ jest mock-fu
 PASS  ./mock-func.test.js
  login 测试组
    ✓ test login1 函数有返回结果 (4 ms)
    ✓ test login2 函数没有返回结果
    ✓ test login3 自定义函数的返回结果
    ✓ test login4 模拟内部的函数(模块) (1 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        1.832 s, estimated 2 s
Ran all test suites matching /mock-fu/i.
✨  Done in 3.59s.
LiuJun-MacBook-Pro:jest liujun$ 

你可能感兴趣的:(单元测试,单元测试)