当前位置:网站首页>This article will introduce you to jest unit test

This article will introduce you to jest unit test

2020-11-06 01:16:28 JackySummer.

Preface

Although the popularity of front-end testing is not high , But it has a great effect on the quality of the project code and the later maintenance project . In this paper, I will talk about Jest unit testing , Because a lot of API See the official website for details .

What is? Jest

Jest It's used to create 、 Execute and build one of the test cases JavaScript test
library . It can be installed and used in any project , Such as Vue/React/Angular/Node/TypeScript etc. .

Use Jest The benefits of

At present, the front-end test is mainly used in the development and application scenarios UI Component library , But it's not just component libraries , Unit testing can also be added to daily project development , Ensure the stability of the project .

What are the benefits of it ?

  • Fast , Easy to use and easy to configure
  • By writing tests , Let the code appear bug It's less likely
  • It's good for writing robust code , Project maintainability enhancement
  • Good test , It has the function of document explanation
  • Reduce... In regression testing bug

Take a chestnut

For example, write an addition and subtraction function

function add(a, b) {
  return a + b
}

function minus(a, b) {
  return a - b
}

Let's start with the simplest function , Suppose you want to test the function , What we're testing , It's his function , Two parameters are passed in when the function is called , Return the result as their added value . For example, incoming add(1, 1), We expect the result to be the result of the addition 2
Write code like this expect(add(1, 1)) === 2, If we encapsulate it more semantically ,expect(add(1, 1)).toBe(2) For our expected test function , To implement this function :

function expect(result) {
  return {
    toBe(actual) {
      if (result !== actual) {
        throw new Error(` Not equal to the expected result . The actual result :${actual}, Expected results :${result}`)
      }
    },
  }
}

Use :

expect(add(1, 1)).toBe(2)
expect(minus(2, 1)).toBe(1)
expect(add(2, 2)).toBe(3) // Error:  Not equal to the expected result . The actual result :3, Expected results :4

If the test doesn't pass, we'll let it throw an error

It's a bit confusing to write like this , Because at first glance, I don't know what I'm testing , therefore , Let's encapsulate one more function , Represents what tests we're doing

// desc  Used to describe test behavior , fn The function that we perform the test for 
function test(desc, fn) {
  try {
    fn()
    console.log(`${desc} Pass the test `)
  } catch (e) {
    console.log(`${desc} The test failed  ${e}`)
  }
}

test(' Addition test ', () => {
  expect(add(1, 1)).toBe(2)
})

test(' Subtraction test ', () => {
  expect(minus(2, 1)).toBe(1)
})

Execute code , Output

 The addition test passed the test 
 The subtraction test passed the test 

This is the simplest test we've ever done , Because our function is relatively simple , So you may feel like you're doing a lot of work .

From the perspective of process , A simple test process ( Input —— Expected output —— The verification results ) as follows :

  1. Introduce the function to be tested
  2. Pass in the test function execution result
  3. Define the expected output
  4. Check that the function returns the expected output

Initialization environment

Create an empty folder and enter initialization

npm init -y

install jest

yarn add --dev jest

stay package.json Configure script commands

{
  "scripts": {
    "test": "jest"
  }
}

New file babel.config.js, Install dependencies and configure

yarn add --dev babel-jest @babel/core @babel/preset-env
// babel.config.js
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      },
    ],
  ],
}

Next, we'll take each of our introductions example.js It's code , Until then *.test.js The file import example.js And test .

matcher Matchers

Use Matchers Allows you to test your code in various ways

Just like the code we wrote above ,jest Provides test,expect,toBe Method

example.js

export const multiply = (a, b) => {
  return a * b
}

New file matcher.test.js

import { multiply } from './example'

test(' Test multiplication ', () => {
  expect(multiply(4, 2)).toBe(8)
})

toBe Use Object.is To test for exact equality . If you want to check the value of an object , Use toEqual Instead of .

matcher.test.js

test(' Test whether the objects are equal ', () => {
  const data = { name: 'jacky' }
  data['age'] = 23
  expect(data).toEqual({ name: 'jacky', age: 23 })
})

function yarn test, You can see that the console shows two tests passed ; If not through the console, it will also prompt which test case is wrong .

When you run the command ,jest Will automatically search for items with .test.js Postfix file , And run the test .

Of course , There are other matchers

test(' matcher ', () => {
  const n = null
  const isTrue = true
  const value = 3
  expect(n).toBeNull() //  Only match  null
  expect(n).toBeDefined() //  Only match  undefined
  expect(n).not.toBeUndefined() //  And  toBeUndefined  contrary 
  expect(isTrue).toBeTruthy() //  Match any  if  The statement is true 

  expect(value).toBeGreaterThan(2)
  expect(value).toBeLessThan(5)
  expect(value).toBeLessThanOrEqual(3)
})

Test asynchronous code

example.js

import axios from 'axios'

export const fetchData = () => {
  return axios.get('https://jsonplaceholder.typicode.com/todos/1')
}

async.test.js

import { fetchData } from './example'

test(' test  async await', async () => {
  const data = await fetchData()
  expect(data.data.id).toBe(1) //  request api Back to id Value is not 1
})

test(' test  Promise', () => {
  return fetchData().then(data => {
    expect(data.data.id).toBe(1)
  })
})

mock function

If we have a lot of asynchronous request functions to test , Will slow the test , Then the above method of using real interface request is not suitable ; Or you want to capture calls to functions , It's time to Mock, It can do :

  1. Capture calls to functions , as well as this And call order
  2. It allows you to configure the return value when testing
  3. Change the internal implementation of the function

mock.test.js

import axios from 'axios'
import { fetchData } from './example'
jest.mock('axios') //  Automatic simulation  axios  modular .

test(' Test request interface ', async () => {
  axios.get.mockResolvedValue({ data: 'hello' }) //  Return false data  { data: 'hello' }  Used for testing 
  await fetchData().then(data => {
    expect(data).toEqual({ data: 'hello' })
  })
})

Maybe you think , What's the use of this test , It's all fake data , As the front end, this side , We just need to make sure that the function is called and returns the result normally ; Of course, this example is relatively simple , When it comes to complex interface testing, there are other things API You can use . Other in-depth and specific interface request testing is what the back-end needs to do .

stay example.js Add a function

//  To execute this function, you need to pass in a callback function , Then the callback function passes a parameter and executes 
export function runFn(fn) {
  fn(' The function executes ')
}

If this is a complex function , We don't want to test just let it execute , You can use it mock To test

test(' Function called ', () => {
  const fn = jest.fn()
  runFn(fn) //  Call function 

  expect(fn).toHaveBeenCalled() //  expect fn Is called the 
  expect(fn).toHaveBeenLastCalledWith(' The function executes ') //  function fn Whether the parameters at the time of being called conform to 
})

Besides , You can also customize the return parameters , The number of times the test was executed and so on , Check official documents for details .

Snapshot

Whenever we want to make sure UI( finger html css etc. ) Or when the configuration file doesn't change , You can use a snapshot to test .

Here's just an example of a configuration file

example.test.js

export function getConfig() {
  return {
    port: 8080,
    url: 'http://localhost:3000',
  }
}

snapshot.test.js

import { getConfig } from './example'

test(' Test the configuration file for changes ', () => {
  expect(getConfig()).toMatchSnapshot()
})

function npm run test, First run , You will find the location of the file and create a folder __snapshots__, There's a snapshot.test.js.snap file , It's about :

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[` Test the configuration file for changes  1`] = `
Object {
  "port": 8080,
  "url": "http://localhost:3000",
}
`;

It contains our configuration information , If you accidentally change the configuration information , An error will be reported during the execution of the test , Because it doesn't match the content of this document ; Then you will know that you should not change the position
For example, change the port to 8081, Run again npm run test

But if it really needs to be changed , Then follow the information in the prompt , Update snapshot , perform :

npm test -- -u

After execution, you will see :

Snapshots:   1 updated, 1 total

If you run the test again this time, there will be no error , The configuration information is updated .

Timers Mocks

When you want to test a function with a timer , Like before 5 What task does the second perform , It's not very convenient for us , To really wait for it to take a certain amount of time to execute , This is a timer function that can simulate .

example.js

export function timerGame(callback) {
  console.log('Ready....go!')
  setTimeout(() => {
    console.log("Time's up -- stop!")
    callback && callback()
  }, 3000)
}
import { timerGame } from './example'

jest.useFakeTimers()

test(' After a certain period of time to test the function ', () => {
  const fn = jest.fn()
  timerGame(fn)
  jest.advanceTimersByTime(3000) //  Three seconds ahead of time 
  expect(fn).toBeCalled() //  Function called 
  expect(fn).toHaveBeenCalledTimes(1) //  The function is executed 1 Time 
})

Test coverage

Add a script command , Output test coverage information as a report

"coverage": "jest --coverage"

Execute the command

You can see the report generated on the terminal , The code test coverage for the above example is 100%, This is because the test function is relatively simple , So it's easy 100%.

At the same time, the project root directory also successfully created a folder coverage, Inside lcov-report Create... In the catalog HTML file , You can view it through the browser .

as follows :

TDD And BDD

Now the most popular unit testing styles are TDD( Test-driven development ) and BDD( Behavior driven development ) Two kinds of . The obvious difference is that one is to write test cases first and then write code , One is to write code first and then write test cases .

TDD

TDD The development process is usually to write test cases first , Then write the code .

For example, write a Todolist, Let's first think about its functions and points for attention , Each function has its own test case , Write test cases , It's not going to work until you write the code ; And then when you're done, you start writing code , Make the test case pass the test , Go on and repeat the steps , Complete development . The quality and maintainability of the code written in this way will also be better .

therefore TDD It's usually used as a unit test , That is, the function of a single component is tested more perfectly , But when several components add up to test this, it may not be perfect .

Function library is widely used in unit testing , Each function can be tested individually and carefully .

Unit testing is relatively independent , But being too independent can also hide some potential problems that can't be detected , This is the time for integration testing .

BDD

BDD The development process is usually to write code first , Write test cases again .

This is more in line with our previous development model , however BDD More attention is paid to whether the overall behavior is in line with expectations , Generally combined with integration testing , In other words, the whole business of many components is tested .

Integration testing focuses on the results , Not the code , More suitable for business development .

Conclusion

Both test styles have their own advantages and disadvantages , Here are just a few examples ; The whole thing is simple to understand , Front end testing allows us to write better code , Reduce bug The birth of ; and , In terms of maintaining some old projects , There are also advantages , For example, when you change the code of an old project , You may be afraid to affect other components or functions, but you don't know , But if there's a test , After running all the test code directly, you can know whether other function code is affected ; And if the old project doesn't write units / Integration testing , For better maintenance , You can also add test code .

If you want to learn more about Jest The content of the test , Of course, go straight Jest Official website I saw , Then in the actual development and application will gradually realize the benefits it brings .

This article code address

版权声明
本文为[JackySummer.]所创,转载请带上原文链接,感谢