Front-end test JEST

Preface : ask a better front-end big God, replies say, good front-end test is a simple thing, especially for front-end UI part of the test. antd on the UI, you can say well done, but saw their related test, there is no perfect. .

For now, the service front-end test and application layer model, combined with relevant information and pit their own problems, to share with you.

A configuration

(1) Select version of jest ( "jest": "^ 20.0.0"):

Projects, such as the compiler tools used babel is not the latest version (6.0.0+), under the current version 24.0.0, the compiler will report an inappropriate tool error, the version down to 20.0.0, can be used. Specific version, you can choose the version according to the project.

(2) .babelrc configuration

Precompiled project, mainly by the babelrc configuration file, presets and plugins two, with these two projects, webpack configuration consistent

presets: ['es2015', 'stage-3'],
plugins: ['transform-class-properties',
          'syntax-dynamic-import',
          'transform-runtime'
         ],
复制代码
(3) jest.config configuration

If the project is not dependent on a plug-in node_modules compiled, you need to make the following settings. Otherwise, .test use cases, we can not rely on the introduction, which will complain.

  transform: {    // 将.js后缀的文件使用babel-jest处理
    "^.+\\.js$": "babel-jest",
  },
  transformIgnorePatterns: // 未编译的依赖,需要在这边配置 ["<rootDir>/node_modules/(?!(snk-sse|javascript-state-machine))"],
复制代码
(4) package configuration
"jest": "jest --coverage"
复制代码

Run npm run jest, it will run all the files with .test.js

Second, the use

(1) calls analog interface

In the node, there's no actual interface calls, if the test involves the interface calls to return data on the need for analog data. The following describes a relatively simple method in which:

The first step, in the same directory VideoService.js, the new mocks folder and the folder inside, (the same file name mock folder must be the actual file name) New VideoService.js

// __mocks__/VideoService.js文件,
export default {
  httpQuery() {
    return new Promise((resolve)=>{
      resolve(123123);
    })
  }
}
复制代码

The second step in the test test.js file, you need to add jest.mock (), RtVideoService.httpChange called VideoService.js interface, here looks __mocks__ the following files and use simulated data VideoService

jest.mock('../services/VideoService.js'); // 必须存在,要不然会报错
test('RtVideoService', () => {
  const obj = { 
    newer: '[email protected]', 
    callback: { error: jest.fn() }
  };
  await RtVideoService.httpChange(null, obj); // 使用了__mocks__下的文件
  expect(obj.callback.next.mock.calls.length).toBe(1);
})

复制代码
(2) a single test run

If the test fails, the first thing to check is that only when running this test, if it still fails. Easily run a test in only Jest - - only temporarily test command changes 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');
});
复制代码
(3) common assertion

Ordinary matcher

  • .toBe - toBe use Object.is exactly equal to test whether
  • .not - opposite use cases for testing
  • .toEqual - if you want to check the value of an object, use toEqual.
test('two plus two is four', () => { 
    expect(2 + 2).toBe(4); 
});
test('object assignment', () => { 
    const data = {one: 1}; 
    data['two'] = 2; 
    expect(data).toEqual({one: 1, two: 2}); 
});
复制代码

Boolean value matcher

  • toBeNull only match null
  • toBeUndefined match only undefined
  • Instead toBeDefined and toBeUndefined
  • toBeTruthy match any if statement is true
  • toBeFalsy match any if statement is false
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();
});
复制代码

String matcher

  • toMatch - character regular expression
  • toHaveLength (number) - determines the length of an object with a length

Digital matcher

  • .toBeGreaterThan () - greater than
  • .toBeGreaterThanOrEqual () greater than or equal
  • .toBeLessThan () - less than
  • .toBeLessThanOrEqual () - less
  • .toBeCloseTo () - Floating-point comparison

Array matcher

  • .toContain (item) - determines whether the array contains a particular child
  • .toContainEqual (item) - determines whether the array contains a particular object

Custom assertion

expect.extend({
  toBeDivisibleBy(received, argument) {
    const pass = received % argument == 0;
    if (pass) {
      return {
        message: () =>
          `expected ${received} not to be divisible by ${argument}`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be divisible by ${argument}`,
        pass: false,
      };
    }
  },
});

test('even and odd numbers', () => {
  expect(100).toBeDivisibleBy(2);
  expect(101).not.toBeDivisibleBy(2);
});
复制代码
There comes to analog interface, the other simulation methods (4) above

1 jest.fn ()

// 举例
test('测试jest.fn()调用', () => {
  let mockFn = jest.fn();
  let result = mockFn(1, 2, 3);

  // 断言mockFn的执行后返回undefined
  expect(result).toBeUndefined();
  // 断言mockFn被调用
  expect(mockFn).toBeCalled();
  // 断言mockFn被调用了一次
  expect(mockFn).toBeCalledTimes(1);
  // 断言mockFn传入的参数为1, 2, 3
  expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
})

// 实际运用
test('answer', () => {
  const fn = { error: jest.fn() };
  ExeService.answer(null, fn);
  expect(fn.error.mock.calls.length).toBe(1); // 测试成功
});
复制代码

jest.fn () Mock created function return values ​​may also be provided, or an internal return Promise objects define the implementation.

test('测试jest.fn()返回固定值', () => {
  let mockFn = jest.fn().mockReturnValue('default');
  // 断言mockFn执行后返回值为default
  expect(mockFn()).toBe('default');
})

test('测试jest.fn()内部实现', () => {
  let mockFn = jest.fn((num1, num2) => {
    return num1 * num2;
  })
  // 断言mockFn执行后返回100
  expect(mockFn(10, 10)).toBe(100);
})

test('测试jest.fn()返回Promise', async () => {
  let mockFn = jest.fn().mockResolvedValue('default');
  let result = await mockFn();
  // 断言mockFn通过await关键字执行后返回值为default
  expect(result).toBe('default');
  // 断言mockFn调用后返回的是Promise对象
  expect(Object.prototype.toString.call(mockFn())).toBe("[object Promise]");
})
复制代码

2, jest.mock () , a function of changing the internal implementation, the above actual cases have, not repeated about estimate

3 jest.spyOn ()

jest.spyOn () method to create a mock same function, but the mock function not only able to capture the function call, you can also perform a normal function of the spy. Indeed, jest.spyOn () is jest.fn () syntax sugar, it creates a mock function and the spy with the same internal function code

jest.mock('../services/VideoService.js'); // 必须存在,要不然会报错
test('RtVideoService', () => {
  const obj = { 
    newer: '[email protected]', 
    callback: { error: jest.fn() }
  };
  await RtVideoService.httpChange(null, obj); // 使用了__mocks__下的文件
  const spyFn = jest.spyOn(VideoService, 'httpChange');
  expect(spyFn).toHaveBeenCalled();
  expect(obj.callback.next.mock.calls.length).toBe(1);
})
复制代码

Third, coverage checks

After performing the write test cases, you might be thinking, what indicators to illustrate what I wrote test cases covering the project was complete?

"test": "jest --coverage"
复制代码

1, first of all, the package in the order, with coverages, this time, the successful implementation of all the use cases, the following output results:

% Stmts is statement coverage (statement coverage): Each statement is not executed?

% Branch branch coverage (branch coverage): is not every if block are executed?

% Funcs coverage function (function coverage): Is not every function call?

% Lines line coverage (line coverage): Each row is not performed?

2, coverage needs to ignore the file or folder

  coveragePathIgnorePatterns: [
    "\\\\node_modules\\\\",
    "<rootDir>/src/utils/",
    "<rootDir>/src/observers/",
    "<rootDir>/lib/",
  ],
复制代码

3, after performing the test, the project will be in the directory to generate coverage folder, which output coverage report

Fourth, resulting from experience

  • 1, in order to carry out jest, Mock, if the code is not suitable for testing, the code will be reconstructed, which makes its own code structure to some extent more reasonable;
  • 2, the test unit may be given a response time of each test, rational division unit testing helps performance problems of location codes;
  • 3, unit testing is a very good business documents, description of each test can reflect the business logic

It IS 官 网

Guess you like

Origin blog.csdn.net/weixin_34211761/article/details/91378990