51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1388|回复: 0
打印 上一主题 下一主题

[原创] 如何用mocha 进行前端单元测试?

[复制链接]
  • TA的每日心情
    无聊
    昨天 09:05
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-11-9 11:07:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    什么是单元测试?
      单元测试( unit testing ),是指对软件中的最小可测试单元进行检查和验证。在前端领域来说,我们主要是针对 JavaScript 的类( class ) 或者方法( function ) 进行单元测试,以增强代码的可靠性和可维护性。下面介绍的是 mocha 单元测试框架。
      mocha 测试框架
      mocha 是一个测试框架,可以通过 npm 全局安装在本地,或者是局部安装在项目中。


    1. <font size="3"># 全局安装

    2.   npm i -g mocha

    3.   # 局部安装在 dev 环境下

    4.   npm i --save-dev mocha</font>
    复制代码


    在测试文件中,写入如下代码:


    1. <font size="3">function add(n, m) {

    2.       return n + m;

    3.   }

    4.   describe("add", () => {

    5.       it('should return 2', () => {

    6.           const count = add(1, 1);

    7.           if ( count !== 2) {

    8.               throw new Error("1 + 1 应该等于2");

    9.           }

    10.       });

    11.   });</font>
    复制代码


    运行 mocha:


    1. <font size="3"> mocha

    2.   # 或

    3.   ./node_modules/.bin/mocha

    4.   # 或指定文件

    5.   ./node_modules/.bin/mocha --file ./src/__test__/*.test.js

    6.   复制代码mocha 命令常用参数

    7.   Options:

    8.       -h, --help                  输出帮助信息

    9.       -V, --version               输出mocha的版本号

    10.       -A, --async-only            强制所有的测试用例必须使用callback或者返回一个promise的格式来确定异步的正确性

    11.       -c, --colors                在报告中显示颜色

    12.       -C, --no-colors             在报告中禁止显示颜色

    13.       -g, --growl                 在桌面上显示测试报告的结果

    14.       -O, --reporter-options <k=v,k2=v2,...>  设置报告的基本选项

    15.       -R, --reporter <name>       指定测试报告的格式

    16.       -S, --sort                  对测试文件进行排序

    17.       -b, --bail                  在第一个测试没有通过的时候就停止执行后面所有的测试

    18.       -d, --debug                 启用node的debugger功能

    19.       -g, --grep <pattern>        用于搜索测试用例的名称,然后只执行匹配的测试用例

    20.       -f, --fgrep <string>        只执行测试用例的名称中含有string的测试用例

    21.       -gc, --expose-gc            展示垃圾回收的log内容

    22.       -i, --invert                只运行不符合条件的测试用例,必须和--grep或--fgrep之一同时运行

    23.       -r, --require <name>        require指定模块

    24.       -s, --slow <ms>             指定slow的时间,单位是ms,默认是75ms

    25.       -t, --timeout <ms>          指定超时时间,单位是ms,默认是200ms

    26.       -u, --ui <name>             指定user-interface (bdd|tdd|exports)中的一种

    27.       -w, --watch                 用来监视指定的测试脚本。只要测试脚本有变化,就会自动运行Mocha

    28.       --check-leaks               检测全局变量造成的内存泄漏问题

    29.       --full-trace                展示完整的错误栈信息

    30.       --compilers <ext>:<module>,...  使用给定的模块来编译文件

    31.       --debug-brk                 启用nodejs的debug模式

    32.       --es_staging                启用全部staged特性

    33.       --harmony<_classes,_generators,...>     all node --harmony* flags are available

    34.       --preserve-symlinks                     告知模块加载器在解析和缓存模块的时候,保留模块本身的软链接信息

    35.       --icu-data-dir                          include ICU data

    36.       --inline-diffs              用内联的方式展示actual/expected之间的不同

    37.       --inspect                   激活chrome浏览器的控制台

    38.       --interfaces                展示所有可用的接口

    39.       --no-deprecation            不展示warning信息

    40.       --no-exit                   require a clean shutdown of the event loop: mocha will not call process.exit

    41.       --no-timeouts               禁用超时功能

    42.       --opts <path>               定义option文件路径

    43.       --perf-basic-prof           启用linux的分析功能

    44.       --prof                      打印出统计分析信息

    45.       --recursive                 包含子目录中的测试用例

    46.       --reporters                 展示所有可以使用的测试报告的名称

    47.       --retries <times>           设置对于失败的测试用例的尝试的次数

    48.       --throw-deprecation         无论任何时候使用过时的函数都抛出一个异常

    49.       --trace                     追踪函数的调用过程

    50.       --trace-deprecation         展示追踪错误栈

    51.       --use_strict                强制使用严格模式

    52.       --watch-extensions <ext>,... --watch监控的扩展

    53.       --delay                     异步测试用例的延迟时间

    54.       --extension                 指定测试文件后缀

    55.       --file                      指定测试文件目录

    56.       ...</font>
    复制代码




    chai 断言库
      为了更友好的显示测试结果,可以使用 chai 断言库:



    1. <font size="3"> # 安装 chai

    2.   npm i --save-dev chai</font>
    复制代码


    使用方法:


    1. <font size="3">// 这里是 es5 的使用方法,使用 ES6 在下面会讲到

    2.   var expect = require('chai').expect;

    3.   function add(n, m) {

    4.       return n + m;

    5.   }

    6.   describe("add", () => {

    7.       it('should return 2', () => {

    8.           const count = add(1, 1);

    9.           expect(count).to.eqls(2);

    10.       });

    11.   });</font>
    复制代码


    使用 ES6
      如果我们要在测试文件中写 ES6 语法的话,需要通过 @babel/register 编译



    1. <font size="3"> # 安装 babel

    2.   npm i @babel/register

    3.   # 运行时添加 --require

    4.   ./node_modules/.bin/mocha --require @babel/register --file ./src/__test__/*.js</font>
    复制代码


    这个时候测试文件就可以写 ES6 的语法了。


    1. <font size="3"> import { expect } from 'chai';

    2.   import { add } from './add';

    3.   describe("add", () => {

    4.       it('should return 2', () => {

    5.           const count = add(1, 1);

    6.           expect(count).to.eqls(2);

    7.       });

    8.   });</font>
    复制代码


    使用 sinon 进行截取和模拟函数
      sinon 提供 stub 和 spy 等函数进行截取和模拟真实函数,以更简单的方式进行测试:



    1. <font size="3"> import { expect } from 'chai';

    2.   import { stub } from 'sinon';

    3.   import calc from './calc';

    4.   // describe 可以嵌套,通常一个测试只测试某一个文件,现在测试 calc 整个文件

    5.   describe("calc", () => {

    6.       // 最好不要这样直接 stub 要测试的方法,不然还测试什么呢?

    7.       decribe('add', () => {

    8.           it('should return 2', () => {

    9.               calcAddStub = stub(calc, 'add').returns(2); // 仅仅为了举例

    10.               expect(calcAddStub()).to.eqls(2);

    11.           });

    12.       });

    13.       // 还可以通过 resolves 模拟异步操作

    14.       decribe('calc time', () => {

    15.           it('should return correct time', async () => {

    16.               const calcTimeStub = stub(calc, 'add').resolves(2); // 仅仅为了举例

    17.               const count = await calcTimeStub();

    18.               expect(count).to.eqls(2);

    19.           });

    20.       });

    21.   });</font>
    复制代码


    使用 enzyme 浅拷贝 React 组件
      如果要测试 React 组件,可以使用 enzyme 进行模拟。



    1. <font size="3"> import { expect } from 'chai';

    2.   import { stub } from 'sinon';

    3.   import { shallow } from 'enzyme';

    4.   import App from './App';

    5.   describe("App", () => {

    6.       const defaultProps = {

    7.           count: 1

    8.       }

    9.       const render = props => shallow(<App {...props} {...defaultProps} />);

    10.       decribe('add', () => {

    11.           it('should return 2', () => {

    12.               const component = render();

    13.               const count = component.instance().add(1, 1);

    14.               expect(count).to.eqls(2);

    15.           });

    16.       });

    17.   });</font>
    复制代码


    使用 Istanbul 查看测试覆盖率
      一般项目都需要达到某一覆盖率以上,以确保代码的健壮性,可以使用 Istanbul (伊斯坦布尔) 包。



    1. <font size="3"># 安装,Istanbul 包改名了,叫 nyc

    2.   npm i --save-dev nyc

    3.   # 运行

    4.   ./node_modules/.bin/nyc ./node_modules/.bin/mocha --require @babel/register --file ./src/__test__/*.test.js</font>
    复制代码


    运行会重新跑一次测试,并且在当前目录生成 .coverage 目录,可以直接在浏览器打开并且查看覆盖率。
      结语
      本篇文章只是简单介绍 js 的单元测试流程,使用的技术包括但不限于 mocha (测试框架), chai (断言库), sinon (截取和模拟函数), enzyme (测试 React 等库), Istanbul (查看覆盖率)。在实际应用中,还需要更多的实际操作,例如测试流程和规范,有的项目中需要测试 渲染的 dom 和 dom 中的属性是否正确,有的仅测试方法,当然还有其他的测试框架例如 jest 等,由于 太懒 篇幅有限,如有写的不对,大佬们请轻喷。


    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-22 16:00 , Processed in 0.069569 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表