preface
Unit testing refers to the examination and verification of the smallest testable units in software. For unit test in unit of meaning, in general, according to the actual situation to determine the specific meaning, such as unit refers to a function in C language, Java unit refers to a class, graphical software can refer to a window or a menu, the vue, react, and presents the frame of the front end, the most important thing is that in view of the component unit tests
Why introduce unit tests?
Present age, a variety of programming language and development framework, thriving integration tools, software engineers, however, are still struggling in the first line, is a bug, legacy code, technical debt, refactoring with, when your project is large enough, in the process of adding modules and components, is is likely to affect the module before. But the affected modules had already been tested, and few testers would retest the system as we iterated. Therefore, the affected module may have an invisible bug deployed online. So we use automated testing. The most important function is to ensure the correct operation of the whole system and the robustness of the system in each iteration of large projects. The following points are summarized:
- Automated testing saves time
- Reduce low-level bugs
- Documentation describing the behavior of components is provided
- Ability to improve code while writing single tests
- Easy to read components and facilitate refactoring
- Prove that your work is done
- Facilitate code review
- The code performance
- Provide some metrics
Unit Test Overview
Unit tests are usually for the smallest part of the application, and in VUE components are the units to be tested (described below)
Let’s start with a simple unit test that uses the sum function to calculate the sum of two numbers in the code.
A unit test is a function that calls a function alone in the source code and asserts that it behaves correctly. Consider the following example, a relatively simple program that exports a sum function and then runs the function, asserting that it will throw an error if it does not return.
// sum.js
export default function sum(a,b){
return a + b
}
// sum.spec.js
import sum from './sum.js'
function testSum(){
if(sum(1.2)! = =3) {throw new Error('the sum (1, 2) not return 3')
}
}
testSum()
Copy the code
Because unit tests are conducted against isolated units, good unit tests, when written, accurately expose code problems.
Also in testing, we might focus on the snapshot test, snapshot test found that is similar to the difference snapshot test will run the program compare screenshots, if there are differences, errors will occur, in vue testing, vueTestUtil provides similar ability, you can compare the js serializable value, in the component is to compare the dom output
Test development patterns
If you’re interested in Test Development, you’ve probably heard of DDD-Test Driven Development and DDD-Behavior Driven Development.
1. Test Driven Development
Test-driven Development, English full name test-driven Development, referred to as TDD, is a new Development method different from the traditional software Development process. It requires that you write test code before you write the code for a feature, and then only write the code for the feature that makes the test pass, and the test drives the development. This helps write clean, usable and high-quality code and speeds up the development process
First of all, the developer before writing business logic, to write some test cases If you run these test cases, will be the result of the failure, because we don’t realize to test the business logic implementation of the business logic to run test cases, check pass, if you are a good developer, may these cases can be through the repair of test cases, Or refactoring
When we develop new features, we repeat the above steps, the core of which is the pre-test case. The flow chart is as follows:
For example: let’s describe TDD with a concrete example. Suppose our requirement is to implement a factorial function. Let’s use JEST to implement this test case
var fac = require(".. /src/index.js");
test("If I input a negative number, I should return NaN.".() = > {
expect(fac(-1)).toBe(NaN);
});
test("Enter 0, should return 1.".() = > {
expect(fac(0)).toBe(1);
});
test("Enter 1, should return 1.".() = > {
expect(fac(1)).toBe(1);
});
test("Enter 2, should return 2.".() = > {
expect(fac(2)).toBe(2);
});
test("If you enter 3, you should return 6.".() = > {
expect(fac(3)).toBe(6);
});
Copy the code
Running this test case is bound to fail because we haven’t implemented the FAC function yet, so let’s implement the factorial function
module.exports = function fac(n) {
if (n < 0) return NaN;
if (n === 0) return 1;
return n * fac(n - 1);
};
Copy the code
Now we run the test case again and get the following result:
As you can see, all the cases have passed, and this is the DEVELOPMENT mode of TDD
2. BDD – Behavior Driven Development
In traditional software development, business people to get the demand, the demand to the demand analysis, demand analysis personnel writing requirements specifications or design, and software developers, according to the specifications for architecture design and code development, then the tester according to specifications. Write test cases to test, from requirements to test delivery, there are a number of different roles, During this period, it is easy to have information loss and misunderstanding, and it is difficult for the R&D team to deliver qualified products as long as there is only one link error.
BDD is an agile software development technique that encourages collaboration between developers, QA, and non-technical or business participants in software and is particularly suitable for agile projects
Here’s an example:
var fac = require(".. /src/index.js");
describe("Verify factorial function faC:".function () {
it("If I input a negative number, I should return NaN.".() = > {
expect(fac(-1)).toBe(NaN);
});
it("Enter 0, should return 1.".() = > {
expect(fac(0)).toBe(1);
});
it("Enter 1, should return 1.".() = > {
expect(fac(1)).toBe(1);
});
it("Enter 2, should return 2.".() = > {
expect(fac(2)).toBe(2);
});
it("If you enter 3, you should return 6.".() = > {
expect(fac(3)).toBe(6);
});
});
Copy the code
Run the test case and get the result:
Content of the code and test results, and comparison the difference is not large, the main difference is the difference between the language, test cases of BDD looks just like looking at a document, the structure is clear, for the team, code reading, promote restructuring has to be reckoned with, when you can fluent when reading the test cases, nature also can write better code.
The examples here only describe the differences from test-driven development and do not represent true behavior-driven development, which is more of a conceptual theory
Conclusion: BDD focuses more on functions than results. To borrow another saying in the industry, BDD helps developers design software, while TDD helps developers test software.
Unit tests in Vue
Unit testing allows you to test separate units of code in isolation. The purpose is to provide developers with confidence in the code. By writing thoughtful and meaningful tests, you can be confident that you can keep your application functional and stable while building new features or refactoring existing code. Unit testing for a Vue application is not significantly different from testing for any other type of application.
Framework to choose
If you are a Vue developer, you should be familiar with the template syntax of Vue components. Template, style, script template syntax is more direct and natural than React Jsx syntax. Vue uses components as minimum test units.
Although unit tests are usually not directly related to the framework, you need to evaluate them for the set of features, performance and support for precompiling single-file components, value generated by single tests, and ease of development.
First-class error reporting
It is critical for a unit testing framework to provide useful error information when a test fails. This is the job of the assertion library. An assertion with high-quality error information minimizes the time required to debug the problem. In addition to simply telling you what test failed, the assertion library should also provide additional context and the reason for the test failure, such as expected results vs. The actual result. Some unit testing frameworks, such as Jest, include assertion libraries. Others, such as Mocha, require you to install assertion libraries separately (usually Chai).
Active community and team
Because the leading unit testing frameworks are open source, having an active community is critical for teams that want to maintain their tests over the long term and ensure that the project itself remains active. As an added bonus, an active community will have more support for you at any time you encounter problems.
Here we consider using the Jest framework, a JavaScript testing framework that focuses on simplicity. One unique feature is the ability to generate snapshots for tests to provide another way to validate application units.
Jest is the most full-featured test runner. It requires minimal configuration, has JSDOM installed by default, built-in assertions, and a very good command-line user experience.
Jest data
Jest’s official website
Vue CLI official plug-in – Jest
Vue provides a handy library of testing tools: Vue Test Utils. We’ll show you how to use Vue Test Utils to unit Test Vue components.
Vue Test Utils
It provides a rich API with powerful features such as rendering component instances, selectors, simulation insertion global components, simulation state, data flow, life cycle, events, and even simulation routing. Let’s try it out.
Installation:
The way to install Vue Test Utils is not too difficult. Let’s first choose a Test runner, either Jest or Mocha, in this case Jest.
If you haven’t already created a project using vue-CLI, you can select Jest when creating a project using vue-cli, the framework will automatically install Vue Test Utils, run:
vue create vue-test
Copy the code
If you already have a project created via vue-CLI, you can run:
vue add @vue/unit-jest
Copy the code
Jest configuration: Jest configuration can be placed in the root directory of Jest. Config. js or Jest
module.exports = {
preset: "@vue/cli-plugin-unit-jest".// Single test plug-in
moduleFileExtensions: ["js"."json"."vue"."less"."css"]./ / the suffix
transform: { // Module parsing
"^.+\\.js$": "<rootDir>/node_modules/babel-jest".".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",},moduleNameMapper: { // Alias recognition
"^ @ / (. *) $": "<rootDir>/src/$1"."\\.(css|less)$": "<rootDir>/tests/mocks/styleMock.js",},Jest-serializer-vue is required for snapshot parsing
snapshotSerializers: ["<rootDir>/node_modules/jest-serializer-vue"].collectCoverage: true.// Coverage directory
coverageDirectory: "report/coverage".// Jest - html-Reporter must be installed
reporters: [
"default"["./node_modules/jest-html-reporter",
{
logo: "https://rdc-test.mingyuanyun.com/static/img/rdc.png".pageTitle: "Single test Report (table)".outputPath: "report/unit-test/index.html".includeFailureMsg: true,},],],};Copy the code
Modules to be installed:
- Jest – Serializer – Vue (Serialization tool)
- Jest-html-reporter (single test report tool, or other tools can be selected)
Once configured, we can happily run the single test
As shown below, this is a very simple click number increment component:
// Increment.js
<template>
<div>
<p>number is {{ count }}</p>
<button @click="increment">increment</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0}; },methods: {
increment() {
this.count++; ,}}};</script>
<style scoped lang="less">
p {
font-size: 2em;
text-align: center;
}
</style>
Copy the code
Vue Test Utils provides methods to implement the wrapper, mount, shallowMount. Once we get the wrapper, we can start using the many interfaces encapsulated in the example
// increment.spec.js
// Import the test toolset
import { mount } from "@vue/test-utils";
import Increment from "@/views/Increment";
describe("Increment".() = > {
// Mount the component to get the wrapper
const wrapper = mount(Increment);
const vm = wrapper.vm;
it("render markup".() = > {
expect(wrapper.html()).toContain("<p>number is 0</p>");
});
// simulate a user click
it("button click should increment the count".() = > {
expect(vm.count).toBe(0);
const button = wrapper.find("button");
button.trigger("click");
expect(vm.count).toBe(1);
});
// Click to view dom
it("button click should increment the count and update the dom".async () => {
expect(wrapper.text()).toContain("1");
const button = wrapper.find("button");
await button.trigger("click");
expect(wrapper.text()).toContain("2");
});
});
Copy the code
Once the unit tests are written, let’s execute them:
npm run test:unit
Copy the code
After running, you can view the single test report report/unit-test/index.html in the root directory of our project. Open it in the browser and you can view it
Open coverage/lcov-report/index.html to see coverage
Ok, so now we have a simple unit test case that uses mounts, wrappers, selectors, event triggers, and more, as well as a number of apis that can be seen in the official documentation
The document
Vue Test Utils official document
The article recommended
Unit testing practices in Vue