Tests are divided into unit tests, integration tests and functional tests.

A Unit Test is a testing practice that examines and validates isolated small units of code, that is, a Test Unit is often an atomic function.

Unit testing is the most basic level of testing practice in the whole test link. Unit testing should cover the low-level details well. Unit tests also require the largest number of use cases for the same requirement. In upper-level integration testing, it is responsible for ensuring that all units are collaborating correctly.

Unit testing is an act of validation, design, and documentation, which has the following advantages for project stability:

  • Ensure the integrity of code quality and functionality.

  • Improving development efficiency and testing during development allows us to find bugs in advance.

  • To facilitate project maintenance, any subsequent code updates must also run through the test cases, even if refactoring or developer changes are required to ensure that the intended functionality is implemented.


In programming, an assertion is a first-order logical design (a logical expression that determines whether the result is true or false). Assertions are used to check whether the program meets expectations at run time. When the program runs to the location of the assertion, if the assertion is not true, the program aborts and throws an exception.

Node provides the assert module. Common assert libraries include should. js and Chai.

However, this is not friendly when it comes to large-scale assertion checking, and it is more common for the unit test framework to log the exception thrown and continue executing, eventually generating a test report. Common third-party testing frameworks include Mocha, Jest.

Test case design

Unit test cases should contain:

  1. Normal input

    Discrete covering parameter range.

  2. Boundary input

    Null value verification, zero value verification, maximum value verification.

  3. Illegal input

    The input data type is invalid and the memory overflow is verified.

Test the framework Jest

Jest is an out-of-the box testing framework with Expect assertions, asynchronous code, Mock, Snapshot, test coverage statistics, and other built-in capabilities for Babel, typescript, Node, React, Vue, Angular, and other built projects.

The installation

  1. Install JEST and related dependencies
yarn add --dev jest
Copy the code
  1. Add test command

    Add “test”: “jest” to the scripts of package.json.

  2. Adding TS support

yarn add --dev ts-jest @types/jest
Copy the code

Create the jest.config.js file in the root directory of the project. See jestjs. IO /docs/config…

Writing test files

Jest can automatically match and execute all test files in a project named.test.js or.spec.js, so we should follow the following naming convention when creating test files: test file name = name of the function being tested +.spec.ts.

For example, if the unit under test is a fenToYuan function in the utils.ts file, the corresponding test file will be named fentoyuan.spec.js.

 * 分转元
 * @param {String|Number} Value Indicates the value, in minutes *@param {Boolean} Whether isBeautify removes the 0 at the end of a value, such as 5.00 to 5 or 5.20 to 5.2. The default is true */
export function fenToYuan (value: any, isBeautify = true) {
    if (!/ ^ -? \d+$/.test(value)) {
        return value || ' '
    const result = (Number(value) / 100).toFixed(2)
    const beaut = result.replace(/^(\d+)(\.00)$/.'$1').replace(/^(\d+\.\d)0$/.'$1')
    return isBeautify ? Number(beaut) : result
Copy the code

Create test case Fentoyuan.spec. ts:

import { fenToYuan } from '@/pages/index/shared/utils'; Test ('convert fen to Yuan', () => {expect(fenToYuan(5.00, true)).tobe (0.05) expect(fenToYuan(0, true)).tobe (0)})Copy the code


Common matchers in Jest are:

  1. ordinary
    • ToBe () & not.tobe (), using object.is ()
    • ToEqual () & not.toequal (), values match, and the object compares each key-value pair.
  2. The true value
    • Boolean
      • toBeTruthy() matches anything that an if statement treats as true
      • toBeFalsy() matches anything that an if statement treats as false
    • null
      • ToBeNull () matches strictly
    • undefined
      • ToBeUndefined () matches undefined exactly
      • ToBeDefined () is the opposite of toBeUndefined
  3. digital
    • ToBeCloseTo (value, numDigits) Comparison of floating point numbers
  4. string
    • toMatch()
  5. iterable
    • toContain()
  6. Throw an error
    • toThrow()

Asynchronous test

Front-end asynchronous logic is all too common, such as requests, timers, and so on. Jest supports asynchronous testing for both callback and Promise scenarios, and Promise supports different writing styles.

  1. callback
  2. promise
  3. resolves / rejects
  4. async / await

Note that when Jest detects an asynchronous test, the default wait time is 5 seconds. If the wait time for an asynchronous operation exceeds that, you need to set the wait time by using Jest. SetTimeout.

DOM test

Jest comes with a jsDOM capability that simulates the DOM environment just as it does in the browser, which means that each DOM API we call can be viewed in the same way as it is in the browser.

If you need to operate dom in unit tests of React projects, it is recommended to install Airbnb’s open source React test library enzyme, which provides a set of concise and powerful APIS and conducts DOM processing in a jja-style way. The development experience is very friendly. It was also featured by React officials.

Simulation button click:

import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';

describe('Test Button component'.() = > {
  it('Test click event'.() = > {
    const mockCallBack = jest.fn();

    const button = shallow((<Button onClick={mockCallBack}>Ok!</Button>));
Copy the code

Hooks and scopes

Some repetitive logic is inevitable during testing, or the configuration of the environment and variables needs to be set repeatedly, which can be achieved through hook functions.

  1. Repeatable, valid only for tests under the describe group
    • BeforeEach (), triggers a callback beforeEach test starts
    • AfterEach (), which triggers a callback afterEach test to restore some mock data
  2. One-shot
    • BeforeAll (), global initialization
    • AfterAll (), global cleanup


Mocks can be divided into Mock data, functions, events, environments, and so on.

In writing unit test cases, it is common to simulate the environment and return values of asynchronous requests.

global.console = { log: jest.fn(), warn: jest.fn(), info: jest.fn() } describe('report error without init cat', () => { afterEach(() => { jest.clearAllMocks() }) test('with full params', () => { const res = reportError(... fullParams) expect(console.warn).toHaveBeenCalledWith( 'Not initCat yet', new Error('test error') ) expect(res).toBe(false) }) })Copy the code

The Mock function is implemented via jest. Fn jest. SpyOn and can be used in conjunction with the matcher.

Function properties:

// This function is called only once

// The first arg when this function is first called is 'first arg'
expect(someMockFunction.mock.calls[0] [0]).toBe('first arg');

// The first time this function is called the second arg is 'second arg'
expect(someMockFunction.mock.calls[0] [1]).toBe('second arg');

// This function is instantiated twice

// The first instantiation of this function returns an object with a name attribute set to 'test '.
Copy the code

The return value of the function:

const myMock = jest.fn();
// > undefined


console.log(myMock(), myMock(), myMock(), myMock());
// > 10, 'x', true, true
Copy the code

Function call validation:

// The mock function was called at least once
// The mock function was called at least once with the specified args
expect(mockFunc).toHaveBeenCalledWith(arg1, arg2);
// The last call to the mock function was called with the specified args
expect(mockFunc).toHaveBeenLastCalledWith(arg1, arg2);
// All calls and the name of the mock is written as a snapshot
Copy the code

A full MOCK environment can be configured in a project during development and testing, as well as through the tool MOCK:

  1. Charles

    Throttle Setting, simulating slow network speed environment.

    Map Remote/Local, which intercepts and simulates the return value of the request.

Test coverage

Jest comes with test coverage, which can be enabled in the jest.config.js configuration file:

// jest.config.js
module.export = {
 // Enable test coverage
 collectCoverage: true.// Specify an overwrite file
 collectCoverageFrom: [
    'src/**/*.ts'.'src/**/*.js'.'src/**/*.vue'.'src/**/*.tsx'.'! **/*.d.ts'.'! **/dist/**/*',].// Require 100% coverage of files
 coverageThreshold: coverTestFiles.reduce((obj, file) = > {
   obj[file] = {
     statements: 100.branches: 100
   returnobj; }, {})};Copy the code

After test coverage is enabled, a Coverage directory will be generated in the project root directory after executing the Jest test. Open the index.html file in the directory to view the test coverage report.

Principles for writing unit tests

  1. Breaking up complex functions makes it easier to override conditions
  2. Mock all calls to the function under test to prevent infiltration
  3. Keep in mind commonly used mutation operator, write single test for substitution
  4. Permutations and combinations are performed in cases where multiple conditions are nested or logical operators are juxtaposed
  5. Refine unit tests against mutation results