Unit Testing benefits

  • Provide documentation that describes the behavior of the component
  • Saves time on manual testing
  • Reduce bugs when developing new features
  • To improve the design
  • Promote the refactoring

Automated testing enables developers on large teams to maintain complex underlying code.

TDD & BDD

Test Driven Development (TDD)

The idea of TDD is to write test cases based on requirements, and then write functional code based on test cases. When a requirement is added or modified, the test case needs to be modified first, and then the code logic needs to be modified according to the test case.

Basic steps:

  1. Write test cases
  2. Run the test, the test case fails the test
  3. Write code to make test cases pass tests
  4. Optimize the code and complete the development
  5. Repeat the above steps

Behavior Driven Development (BDD)

In contrast to TDD, BDD is developed based on requirements, and after the functionality is developed, start writing test code to test it.

Basic steps:

  1. Write the code
  2. Write test cases that fail
  3. Write code to make the test case pass
  4. Optimize the code and complete the development
  5. Repeat the above steps

Currently we use BDD model.

Jest configuration

If the project is built using vue-CLI, it will be asked to use unit tests during initialization. Simply select Jest step by step and vue Test Utils will be automatically installed. Vue Test Utils is the official unit Test utility library of VUe.js, providing a bridge between JEST and Vue. Exposing interfaces that make it easier to write unit tests for Vue applications through Jest.

In the generated project root directory, there will be a jest.config.json file. The default used for the CLI automatic generation is @vue/cli-plugin-unit-jest. This is where we can personalize jEST. Here is an example of a configuration document. Parameters in the configuration document are described

Module.exports = {// tells jest to resolve the file moduleFileExtensions: ['js'.'jsx'.'json'.'vue'], // tell jest where to find moduleDirectories, with modules moduleDirectories in webpack: ['src'.'node_modules'], // tell jest how to escape for different types of files'^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest'.'^.+\\.js$': '<rootDir>/node_modules/babel-jest'.'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub'.'^.+\\.jsx? $': 'babel-jest'.'^.+\\.ts? $': 'ts-jest'}, // tells jest which files to ignore during editing. Default is all files in node_modules.'<rootDir>/node_modules/'
        + '(? ! (vue-awesome|veui|resize-detector|froala-editor|echarts|html2canvas|jspdf))'], // alias, same as in webpackalias
    moduleNameMapper: {
        '^src(.*)$': '<rootDir>/src/$1'.'^ @ / (. *) $': '<rootDir>/src/$1'.'^block(.*)$': '<rootDir>/src/components/block/$1'.'^toolkit(.*)$': '<rootDir>/src/components/toolkit/$1'
    },
    snapshotSerializers: [
        'jest-serializer-vue'], // Tell Jest where to find the test file we wrotetestMatch: [
        // '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
        '**/tests/unit/**/Test.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'], // setupFiles: ['jest-canvas-mock']};Copy the code

One thing to note is that because veui is used in the project, node_modules references the source code and is not escaped by Babel. So you need to tell Jest in the transformIgnorePatterns that you need to compile it. The same applies to other imported third-party libraries.

Vue Test Utils

Before writing the Test cases, let’s take a quick look at some of the Vue Test Utils apis and wrappers.

ShallowMount: creates a Wrapper containing the Vue component to be mounted and rendered. ShallowMount: does the same as mount, but does not render the child component. Render an object as a string and return a Cheerio wrapper createLocalVue: Returns a Vue class for you to add components, mix, and install plug-ins without polluting the global Vue classCopy the code
Wrapper: A Wrapper is a wrapper that contains a mounting component or vnode and a method to test that component or Vnode. Wrapper.vm: gives access to all methods and properties of an instance wrapper.setData() : same as Vue. Set () wrapper.trigger(): asynchronously triggers an event wrapper.find(): returns a DOM node or Vue componentCopy the code

Specific APIS and Warpper methods and examples can be found here.

Demo

// test.spec.js
import { shallowMount } from '@vue/test-utils'
import Test from '@/components/Test'

const factory = (values = {}) => {
  return shallowMount(Test, {
    data () {
      return {
        ...values
      }
    }
  })
}

describe('Foo', () => {
  it('renders a welcome message', () => {
    const wrapper = factory()

    expect(wrapper.find('.message').text()).toEqual("Welcome to the Vue.js cookbook")
  })

  it('renders an error when username is less than 7 characters', () => {
    const wrapper = factory({ username: ' ' })

    expect(wrapper.find('.error').exists()).toBeTruthy()
  })

  it('renders an error when username is whitespace', () => {
    const wrapper = factory({ username: ' '.repeat(7) })

    expect(wrapper.find('.error').exists()).toBeTruthy()
  })

  it('does not render an error when username is 7 characters or more', () => {
    const wrapper = factory({ username: 'Lachlan' })

    expect(wrapper.find('.error').exists()).toBeFalsy()
  })

  it('snapshot test', () => {
    const wrapper = factory()

    expect(wrapper.html()).toMatchSnapshot()
  })
})
Copy the code

Generate test coverage reports

Json can be configured to generate test coverage reports. Generating reports will slow down the speed of single tests. This is disabled by default and needs to be manually enabled.

module.exports = {
  preset: '@vue/cli-plugin-unit-jest'// Enable test report collectCoverage:true// Count where the file collectCoverageFrom: ["**/src/components/**".! "" **/node_modules/**"]}Copy the code

The generated reports are in the coverage folder of the root directory and can be opened on the package.json configuration command line or viewed on the console.

"scripts": {
    "coverage": "open ./coverage/lcov-report/index.html"
  },
Copy the code

%Stmts(statement coverage): is every statement executed? %Branch(Branch coverage): indicates the Branch coverageifDid the blocks execute? %Funcs(branch coverage): function coverage, is every function called? %Lines(line coverage): is every line executed?Copy the code

Refer to the article

  1. jest
  2. Vue Test Utils
  3. Element source