百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

前端如何做好单元测试 前端开发自动化单元测试

zhezhongyun 2024-12-16 17:34 62 浏览

简介

日常我们都忙于写bug,有时候不妨停下脚步,找找bug。测试广义上分为黑盒测试和白盒测试。单元测试属于后者,是在知道程序运行逻辑的基础上,设计测试用例,确保程序模块行为与我们预期一致。

前端做单元测试的不多,但是并不代表不必要,对于一些复杂的数据处理、公共类库等,单元测试是非常有必要的,代码只要有修改,就是有风险的,检验代码正确与否,最安全的方法就是通过设计的所有测试用例。通过本文,你将会收获以下内容:

  1. Node.js中如何做单元测试,如何生成测试报告与测试覆盖率
  2. vue.js单文件组件如何从零开始搭建单元测试环境

Node.js单元测试

巧妇难为无米之炊,在做单元测试前,我们需要借助一款测试框架与一个断言库,测试框架是辅助我们编写测试用例,而断言主要是用来判断预期输出与实际输出是否一致。本文测试框架选用mocha,断言采用expect.js。

CommonJS与ES6模块化区别

现在前端开发环境几乎都运行在Node.js中,只是最后打包成静态资源文件。所以单纯只想针对单纯项目中JavaScript文件进行单元测试,会因为模块化的差异而执行失败,因为ES6中使用的是import/export,而CommonJS中使用的是require/module.exports,想了解Node.js 如何处理 ES6 模块,可以参考阮老师文章。本文推荐一个第三方类库esm,仅需两步就能实现Node.js加载ES6 module。使用流程如下:

  • 安装
npm install esm -D
  • 使用
const $require = require('esm')(module)
// 注意:如果是export default,导入的模块需要通过.default获取
const TestModule = $require('ES6Module.js')

测试代码

以下为测试代码,主要测试加法运算及函数柯里化处理过程是否正确。

class Calc {
  constructor() {
    this.add = this.addFun()
  }
  // 函数柯里化
  addFun () {
    let args = []
    let calcFun = function (...params) {
      args = args.concat(params)
      return args.reduce((total, current) => {
        return total + current
      }, 0)
    }

    calcFun.clear = function () {
      args = []
    }

    return calcFun
  }
}

export default = Calc

编写测试用例

测试框架采用mocha,一般编写单元测试用例,离不开describeitdescribe类似于开发中的class,是一类测试用例的集合;it相当于普通function,是一个具体测试用例实现。如下为简单的测试用例,简单罗列了普通测试与异步测试的基本使用,更多使用方法可以参考mocha官网

const Calc = require('../class/calc.js')
const expect = require('expect.js')

const calcInstance = new Calc()
describe('Test calc add operation', function () {
  it('should 1 + 2 === 3', function () {
    expect(calcInstance.add(1, 2)).to.be(3)
  });

  it('should summary + 2 === 4', function () {
    expect(calcInstance.add(2)).to.be(5)
  });

  it('should 1 + 2 === 3 after clear', function () {
    // 指定当前测试用例超时时间
    this.timeout(0)
    calcInstance.add.clear()
    // 异步测试
    return new Promise(resolve => {
      setTimeout(() => {
        resolve()
      }, 2000)
    }).then(() => {
      expect(calcInstance.add(1, 2)).to.be(3)
    })
  });
})

单元测试指标

覆盖率简述

覆盖率是单元测试核心指标,又细分为语句覆盖率(Statements)、分支覆盖率(Branches)、函数覆盖率(Functions)、行覆盖率(Lines)。一个比较好的单元测试用例,要保证被测试代码的关键逻辑都被测试用例覆盖到。如下为Calc类的单元测试覆盖率情况。

单元测试覆盖率统计

开源组件nyc可以帮助我们统计覆盖率情况。

  • 安装
npm install nyc -D
  • 配置文件
// nyc.config.js
module.exports = {
  all: true,
  include: [ // 包含测试文件
    "web/src/lib/**.js",
    ".electron/class/**.js",
    "web/src/**/*.js",
    "web/src/**/*.vue"
  ],
  exclude: [ // 排除测试文件
    "web/test/*.spec.js",
    ".electron/test/*.spec.js"
  ],
  checkCoverage: false, // 测试基准覆盖率
  reporter: ['text', 'html'] // 测试报告格式
}
  • 使用
// package.json
"test-add": "nyc mocha .electron/test/calc.spec.js"

可视化单元测试报告

mocha官方推荐使用mochawesome用于生成可视化测试报告,使用非常简单。

  • 安装
npm install mochawesome -D
  • 使用
// package.json
"test-add-reporter": "mocha .electron/test/calc.spec.js --reporter mochawesome --reporter-options reportDir=mochaReporter,reportFilename=addReporter"

注意事项

编写单元测试用例时,不仅要考虑测试覆盖率,还要考虑测试用例设计。合格的测试用例不仅要包含正常情况输入输出,也要包含异常情况输入输出的判断,不能以开发的思维去编写测试用例。

vue组件的单元测试

vue单文件组件测试官方脚手架也有集成,但是还是要抱着试一试的态度,去学习下如何从零开始搭建一个vue单文件组件测试环境。

.vue文件并不能直接执行,需要对其进行打包编译,转换成浏览器能识别的静态资源文件才行。目前有开源的工具mochapack可以提供这种能力。见名知意,普通mocha测试用例是可以直接执行的,但是遇到非javascript语法,就会执行报错。mochapack主要功能是在测试用例执行前利用webpack对测试用例进行编译转换,这样就不用担心执行出错。具体配置如下:

// 基础配置
{
  "test-vue-sfc": "mochapack  --webpack-config ./build/webpack.test.config.js --require ./web/test/setup.js web/test/demo.spec.js"
}
  • --webpack-config 指定webpack配置文件
  • --require 指定环境依赖状态,如nodejs中不存在dom,需要引入js-dom
  • web/test/demo.spec.js 需要执行的测试用例

vue测试用例编写

测试用例是用nodejs执行,并没有浏览器环境,所以我们借助官方提供的测试工具@vue/test-utils对组件进行模拟挂载、点击等。使用方法也比较简单,以下为简单的测试用例。

import Vue from 'vue'
import ElementUI from 'element-ui'
import TestDemo from '../src/components/test-demo.vue'
import { shallowMount } from '@vue/test-utils'

Vue.use(ElementUI)

describe('Test test-demo.vue', function () {
  this.timeout(0)
  const wrapper = shallowMount(TestDemo)
  wrapper.vm.count = 1
  it('should summary === 1', function () {
    expect(wrapper.vm.summary).to.be(1)
  });
})

结语

对于通用性、处理逻辑复杂等模块单元,做单元测试收益会很大的,至少每次改动的对错,都能有一个较明显的反馈。单元测试不仅要注意一定程度的覆盖率,也要注意测试用例设计的合理性。完整代码可以参考electron-demo,这个项目是electron开发demo,里面是本人日常开发中常见的坑点,有兴趣的可以关注下。

相关推荐

perl基础——循环控制_principle循环

在编程中,我们往往需要进行不同情况的判断,选择,重复操作。这些时候我们需要对简单语句来添加循环控制变量或者命令。if/unless我们需要在满足特定条件下再执行的语句,可以通过if/unle...

CHAPTER 2 The Antechamber of M de Treville 第二章 特雷维尔先生的前厅

CHAPTER1TheThreePresentsofD'ArtagnantheElderCHAPTER2TheAntechamber...

CHAPTER 5 The King'S Musketeers and the Cardinal'S Guards 第五章 国王的火枪手和红衣主教的卫士

CHAPTER3TheAudienceCHAPTER5TheKing'SMusketeersandtheCardinal'SGuard...

CHAPTER 3 The Audience 第三章 接见

CHAPTER3TheAudienceCHAPTER3TheAudience第三章接见M.DeTrévillewasatt...

别搞印象流!数据说明谁才是外线防守第一人!

来源:Reddit译者:@assholeeric编辑:伯伦WhoarethebestperimeterdefendersintheNBA?Here'sagraphofStea...

V-Day commemorations prove anti-China claims hollow

People'sLiberationArmyhonorguardstakepartinthemilitaryparademarkingthe80thanniversary...

EasyPoi使用_easypoi api

EasyPoi的主要特点:1.设计精巧,使用简单2.接口丰富,扩展简单3.默认值多,writelessdomore4.springmvc支持,web导出可以简单明了使用1.easypoi...

关于Oracle数据库12c 新特性总结_oracle数据库12514

概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...

【开发者成长】JAVA 线上故障排查完整套路!

线上故障主要会包括CPU、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。同时例如jstack、jmap等工具也是不囿于一个方面的问题...

使用 Python 向多个地址发送电子邮件

在本文中,我们将演示如何使用Python编程语言向使用不同电子邮件地址的不同收件人发送电子邮件。具体来说,我们将向许多不同的人发送电子邮件。使用Python向多个地址发送电子邮件Python...

提高工作效率的--Linux常用命令,能够决解95%以上的问题

点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...

linux常用系统命令_linux操作系统常用命令

系统信息arch显示机器的处理器架构dmidecode-q显示硬件系统部件-(SMBIOS/DMI)hdparm-i/dev/hda罗列一个磁盘的架构特性hdparm-tT/dev/s...

小白入门必知必会-PostgreSQL-15.2源码编译安装

一PostgreSQL编译安装1.1下载源码包在PostgreSQL官方主页https://www.postgresql.org/ftp/source/下载区选择所需格式的源码包下载。cd/we...

Linux操作系统之常用命令_linux系统常用命令详解

Linux操作系统一、常用命令1.系统(1)系统信息arch显示机器的处理器架构uname-m显示机器的处理器架构uname-r显示正在使用的内核版本dmidecode-q显示硬件系...

linux网络命名空间简介_linux 网络相关命令

此篇会以例子的方式介绍下linux网络命名空间。此例中会创建两个networknamespace:nsa、nsb,一个网桥bridge0,nsa、nsb中添加网络设备veth,网络设备间...