可以进行单元测试么_前端与单元测试

d5e76515d19c93d1aeea44be6be88551.png

先来几个专业词汇,这样显得高大上一点(不存在的=。=)

BDD: Behavior-Driven Development (行为驱动开发)TDD: Test-Driven Development (测试驱动开发)ATDD: Acceptance Test Driven Development(验收测试驱动开发)

好,说完了,然后我们废话不多说,直接进入正题。我会从多个测试框架入手,结合各种断言库,用代码方式说明。


单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证。

当今所有著名的框架都要进行单元测试,经过测试的框架,它的信任度显然高于未测试的框架。

这里,我们介绍一下karma这个前端的单元测试框架。

4c567b916e296056d25d4ea8e73d387b.png
Spectacular Test Runner for Javascript​karma-runner.github.io

首先我们来安装一波:
新建一个文件夹,然后在空文件夹中打开终端输入

npm init -y
(sudo) npm install karma-cli -g
npm install karma karma-jasmine karma-chrome-launcher jasmine-core --save-dev
npm install karma-phantomjs-launcher --save-dev

b809e3745b98b47697e4e670227fe9fe.png

你安装karma-cli这个倒是说得过去,可是这个jasmine是啥,这个chrome-launcherphantomjs-launcher又是啥?

没错,单说测试框架是不完整的,必须要有断言库与之相配合,这里的jasmine就是断言库。

48a8a443374daaab5d736b0a815e787c.png

啥是断言(assert)

根据概念:

断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。

一言以蔽之,老子/老娘说啥就是啥!听起来好像挺霸道的。那么具体呢?

顺着karma的正常流程向下走,我们来写一个简单的单元测试。在终端输入:

karma init

你会发现,需要做一个调查问卷了,问题如下:

> 请问你要用哪种测试框架呢?
> 按tab键选择,按回车键进入下一个问题。
> jasmine 
(因为我们安装的是jasmine,选什么断言库都别忘了安装一下)> 您想要使用Require.js么?  
> 选择yes的话,会安装Require.js插件。
> 按tab键选择,按回车键进入下一个问题。  
> no 
(这里我们选择no)> 你想要在什么浏览器中测试呢?  
> 按tab键选择,输入空字符串进入下一个问题。  
> Chrome
> PhantomJS
>注:上面的选择这两个浏览器的原因是我们之前安装了这两个浏览器的启动器(launcher)> 需要测试的源文件和测试命令文件放在哪呢?
你可以使用通配符(glob patterns)来匹配文件,比如:"js/*.js" 或 "test/**/*Spec.js"
输入空字符串进入下一个问题。 
>
(这里先留空,可根据测试情况灵活配置)>在符合匹配的文件中有哪些文件可以排除在外呢?
你可以使用通配符来匹配文件,比如:"**/*.swp"
输入空字符串进入下一个问题。 
> > 你想要Karma根据文件的变化立即做出响应么?
> yes

之后,你就会发现你的文件夹里多了一个文件:

e3829e78888ddc09bf25b58e2f20914b.png

打开这个文件,你会发现里面是一个配置项函数:

module.exports = function(config) {basePath: '', // 根路径将会同files和excluede项中的相对路径相关联frameworks: ['jasmine'], // 所使用的测试框架files: [], // 这里是需要测试的文件列表,有多种配置方式exclude: [], // 测试过程中排除在外的文件列表reporters: ['progress'], // 测试结果的汇报方式,port: 9876, // web服务器接口colors: true, // 是否使用彩色报告logLevel: config.LOG_INFO, // 日志级别,可配置的值有: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUGautoWatch: true, // 是否自动观测文档改变并执行测试命令browsers: ["Chrome", "PhantomJS"], // 用哪些浏览器测试呢singleRun: false, // 持续集成模式,如果设置成true,Karma将自行捕获浏览器,运行测试并根据结果退出,concurrency: Infinity // 并发数,同时跑多少个浏览器进行测试,默认无上限
}

默认会生成的配置项就是上面这些,更完整的配置请点我
这里稍微提一下browsers配置项,它可以配置高达8种浏览器:

a0711a9462d5e983db4fca5ef6af26f0.png

每一种都需要安装对应的launcher。其中有两个需要注意chromeHeadlessPhantomJS。这两个是无头浏览器。所谓无头浏览器就是没有脑袋的浏览器

8f843cffd46319c864c0fa9a31495b06.png
无头浏览器即headless browser,是一种没有界面的浏览器。既然是浏览器那么浏览器该有的东西它都应该有,只是看不到界面而已。因此这种浏览器没有渲染UI的过程,用于测试时的速度很快。

这就回答了上文launcher是啥的问题。毕竟,没有浏览器靠脑补可没法测试啊(真实)

言归正传。我们回到karma测试本身。接下来,我们修改一下配置:

files: ["src/srcTest/**/*.js", "test/unit/**/*.js"]

注意,上述写法只是配置写法中的一种, 配置的文件位置也是随您自己指定,更详细的配置请点我

采用上文写法的话,我们在files数组里面配置的第一项是需要测试的文件,第二项就是用什么方法去测试它的文件

因此,我们也在文件里创建对应的文件夹:

681f75e41cdf0cbffd7853eda5c100e3.png

这里有一个要注意的点。我们的需要测试的文件和测试驱动文件的名字是一一对应的,区别就在于测试驱动文件的名字后要加上.spec

那么我们就在srcTest的文件里面写点什么吧....

newBee.js

// 减法函数
function minus(x) {return function(y) {return x - y;};
}

testKarma.js

// 加法函数
function add(x) {return function(y) {return x + y;};
}// 乘法函数
function multi(x) {return function(y) {return x * y;};
}//if函数测试
function ifTest(boolean) {if (boolean) {return "热热";} else {return "凉凉";}
}// 反转字符串
function reverseStr (string) {return string.split("").reverse().join("");
}

e42d57c1abe155fd644142d1d98d87c3.png

那么接下来,就在.spec文件里写入对应的测试断言。我滴个龟龟,终于说到断言了。

因为我们这里使用的是Jasmine,因此就先放一下它的官网。

b140912442d13b35bc4aa484e3bdbcde.png
Global​jasmine.github.io

我们结合实例来说文档

newBee.spec.js

describe("newBee单元测试", function() {it("减法函数测试", function() {var minus7 = minus(7);expect(minus7(6)).toBe(0);});
});

testKarma.spec.js

describe("testKarma单元测试", function() {it("如果函数测试", function() {expect(ifTest(true)).toBe(true);expect(ifTest(false)).toBe("凉凉");});it("回文函数测试", function() {expect(reverseStr('abc')).toEqual('cba');})});

基本的格式就是这样的,下面来解释一下

// 分组describe(), 这个是可以嵌套的,并且每个单独的测试都有beforeAll, afterAll, beforeEach和afterEach
describe("这里写测试群组的名称", function(){// 具体的测试,it(), 当其中所有的断言都为true时,则通过;否则失效。it('这里写具体测试的名称', function(){var a = true;// 期望, expect()。 匹配,to*()// 每个匹配方法在期望值和实际值之间执行逻辑比较// 它负责告诉jasmine断言的真假,从而决定测试的成功或失败// 木有错,老子/老娘说啥就是啥expect(a).toBe(true); // 这是肯定断言expect(!a).not.toBe(true); // 这是否定断言// jasmine内置的匹配方法有很多,亦可自定义匹配方法// toBe()// toEqual()// toMatch()// toBeUndefined()// toBeNull()// toBeTruthy()// toContain()// toBeLessThan()// toBeCloseTo()// toThrowError()// 等等等等})
})

那么,测试方法写完了,我们来实际运行一下测试吧。打开终端,输入:

karma start

就会在终端看到

a331798a52cfbc9aa325a2d1610e1556.png

可以看到,我们的测试在Chrome和PhantomJS浏览器中分别测试了的5个方法,都有2个没有通过测试,没错,我们当初在写测试的时候故意写错了(这是真的)。

那么我们把测试修改成真值。

newBee.spec.js

describe("newBee单元测试", function() {it("减法函数测试", function() {var minus7 = minus(7);expect(minus7(6)).toBe(1);});
});

testKarma.spec.js

it("如果函数测试", function() {expect(ifTest(true)).toBe("热热");expect(ifTest(false)).toBe("凉凉");
});

结果是:

e1f5a64abbd3193f5d22f655d4d7e014.png

全部SUCCESS, 撒花。

到这里,一个基本的测试流程就走完了。然而,这并非终点。

其实,还能更进一步的。我们打开终端:

npm install karma-coverage --save-dev

然后打开karma.conf.js, 添加一些配置项

// 这里配置哪些文件需要统计测试覆盖率,例如,如果你的所有代码文件都在src文件夹中,你就需要如下配置
preprocessors: {"src/srcTest/*.js": "coverage"
},
// 新增coverageReporter选项
// 配置覆盖率报告的查看方式,type查看类型,可以取值html、text等等,dir输出目录
coverageReporter: {dir: "docs/unit",reporters: [{type: "html",subdir: "report-html"}]
},
reporters: ['progress', "coverage"] // 没错,reporters里面新增了一个coverage

然后保存,再运行一次karma start

接着会发现你的项目里多了一个文件夹

fda3d0530a10513497978f3c061695ca.png

用浏览器打开index.html。就会看到

5eaef53af2fe2fe2f5a8eaa0f351eda7.png

这就是你所写的js的测试覆盖率。

这样看起来是不是高大上了一些呢?

这里就有一个问题了。普通的js可以测试,可是我是写Vue的啊,Vue组件怎么测试呢?很简单,Vue官网有非常详细的测试教程。甚至还有专用的测试工具和测试说明

cb94a3739d107ef74b187ad70633c01c.png

彳亍口巴,你说的这些个单元测试看起来花里胡哨的,实际作用是什么呢?

单元测试的好处

  1. 单元测试不但会使你的工作完成得更轻松。而且会令你的设计会变得更好,甚至大大减少你花在调试上面的时间。
  2. 提高代码质量
  3. 减少bug, 快速定位bug
  4. 使修改和重构可以更放心
  5. 显得专业

单元测试的缺点

开发人员要花费时间在写测试代码上,然而又不会给你加工资...
小项目写测试只能单纯的增加开发时间和成本,然而又不会给你加工资...
我写了测试除了懂测试的人能看懂,别人又不知道,然而还不会给你加工资...

336b309ab9c1f65b93eec0660303c7e4.png

别别别,别打我...你先听我道(hu)理(jiao)讲(man)完(chan)。

  1. 对于所编写的代码,你在调试上面画了多少时间?
  2. 对于以前你自认为正确的代码,而实际上这些代码却存在重大的bug,你花了多少时间在重新确认这些代码上面?
  3. 对于一个别人报告的bug,你花了多少时间才找出导致这个bug的源码位置?

对于那些没有使用单元测试的程序员而言,上面这些问题所耗费的时间的是逐渐增加的,而且项目越深入,花费的时间越多;另一方面,适当的单元测试却可以很大程度地减少这些时间,从而为你腾出足够的时间来编写所有的单元测试——甚至可能还有剩余的空闲时间。

更加真实的是,主流的框架必须要写测试

不想当程序员的设计师不是好运维。 ----鲁迅

作为一个程序员,如果你想要让自己写的框架放到github和npm上能够为世界上的其他人所用。那么一个最基本的前提就是————代码没有BUG。可是,你的怎么向语言不通思维不同的人解释你的JavaScript库确实足够健壮呢。这个时候就需要单元测试出场了。

主流前端框架虽然在所使用的测试库(karma、jest、QUnit)和断言库(assert、jasmine、 chai)上略有差别,但Vue、React、Angular、Underscore甚至是jQuery都写了单元测试。

来个石锤

e6fec5e1fcb0d96f7e0ee8695388000c.png

下面我们看一看Vue的测试是怎么写的:

git clone https://github.com/vuejs/vue.git
npm install
npm run test unit // 这里可以看到单元测试
npm run test // 这里就看全部的测试

Vue的测试覆盖率为

57e5636d86ffbb015c0c9af45830dc65.png

举例:v-show的测试

// import Vue from 'vue'describe('Directive v-show', () => {it('should check show value is truthy', () => {const vm = new Vue({template: '<div><span v-show="foo">hello</span></div>',data: { foo: true }}).$mount()expect(vm.$el.firstChild.style.display).toBe('')})it('should check show value is falsy', () => {const vm = new Vue({template: '<div><span v-show="foo">hello</span></div>',data: { foo: false }}).$mount()expect(vm.$el.firstChild.style.display).toBe('none')})it('should update show value changed', done => {const vm = new Vue({template: '<div><span v-show="foo">hello</span></div>',data: { foo: true }}).$mount()expect(vm.$el.firstChild.style.display).toBe('')vm.foo = falsewaitForUpdate(() => {expect(vm.$el.firstChild.style.display).toBe('none')vm.foo = {}}).then(() => {expect(vm.$el.firstChild.style.display).toBe('')vm.foo = 0}).then(() => {expect(vm.$el.firstChild.style.display).toBe('none')vm.foo = []}).then(() => {expect(vm.$el.firstChild.style.display).toBe('')vm.foo = null}).then(() => {expect(vm.$el.firstChild.style.display).toBe('none')vm.foo = '0'}).then(() => {expect(vm.$el.firstChild.style.display).toBe('')vm.foo = undefined}).then(() => {expect(vm.$el.firstChild.style.display).toBe('none')vm.foo = 1}).then(() => {expect(vm.$el.firstChild.style.display).toBe('')}).then(done)})it('should respect display value in style attribute', done => {const vm = new Vue({template: '<div><span v-show="foo" style="display:block">hello</span></div>',data: { foo: true }}).$mount()expect(vm.$el.firstChild.style.display).toBe('block')vm.foo = falsewaitForUpdate(() => {expect(vm.$el.firstChild.style.display).toBe('none')vm.foo = true}).then(() => {expect(vm.$el.firstChild.style.display).toBe('block')}).then(done)})it('should support unbind when reused', done => {const vm = new Vue({template:'<div v-if="tester"><span v-show="false"></span></div>' +'<div v-else><span @click="tester=!tester">show</span></div>',data: { tester: true }}).$mount()expect(vm.$el.firstChild.style.display).toBe('none')vm.tester = falsewaitForUpdate(() => {expect(vm.$el.firstChild.style.display).toBe('')vm.tester = true}).then(() => {expect(vm.$el.firstChild.style.display).toBe('none')}).then(done)})
})

只要你的测试覆盖率足够高,你就可以在著名的GitHub装逼网站Codecov搞一个覆盖率标签了。就像下面这个:

ae735767b79d0f15a5ee18c5632dbb90.png

怎么样,这样你所写的框架,是不是就逼格满满?

02843ef8049471bce64ebb118f96c601.png

所以你还在等什么,测不了吃亏,测不了上当,赶紧在自己的代码中加入测试吧,~~只要998~~,代码逼格带回家!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/257764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UWP--页面传值

//匿名对象private void Button1_OnClick(object sender, RoutedEventArgs e){this.Frame.Navigate(typeof(PageNavigate2), new { id 1, name "LBI" });}//利用反射获取protected override void OnNavigatedTo(NavigationEventArgs e){var parameter e.Parameter…

Android 4.4 KitKat, the browser and the Chrome WebView

Having V8 as the JavaScript engine for the new web view, the JavaScript performance if much better, besides general performance on CSS thanks to hardware acceleration Android 4.4 KitKat, the browser and the Chrome WebView转载于:https://www.cnblogs.com/dais…

excel 行高 上下留白_拒绝加班,工作中最常用的57个Excel小技巧来了!

今天高顿君分享的 Excel小技巧&#xff0c;全是工作是最常用且简单易操作的&#xff0c;共57个&#xff0c;希望对同学们有所帮助。&#xff08;适合版本 Excel2007及以上&#xff09;一、文件操作1、为excel文件添加打开密码文件 - 信息 - 保护工作簿 - 用密码进行加密。2、为…

经验分享:三步走教你升级企业NAS设备

前几年凡是对于数据存储有需求的企业都已经购买了相关的NAS产品&#xff0c;不过电脑和网络升级换代是比较频繁的&#xff0c;几年过去了中小企业对数据存储的需求也水涨船高&#xff0c;然而面对当初的NAS存储设备该如何处理呢&#xff1f;扔掉可惜使用又不如意的鸡肋问题能够…

C#索引器

索引器允许类或者结构的实例按照与数组相同的方式进行索引取值&#xff0c;索引器与属性类似&#xff0c;不同的是索引器的访问是带参的。 索引器和数组比较&#xff1a; (1)索引器的索引值(Index)类型不受限制 (2)索引器允许重载 (3)索引器不是一个变量 索引器和属性的不同点 …

获取访客进站关键词_拼多多访客突然下降是为什么?拼多多访客突然暴涨又是怎么回事?...

在当下这个互联网时代&#xff0c;可以说流量就代表这金钱。这一点在做电商的商家那里表现的就更为直观了&#xff0c;如果你做了一个拼多多的店铺&#xff0c;之前店铺的流量一直都比较好&#xff0c;而现在拼多多店铺的流量忽然下降了&#xff0c;那么店铺中的销售额就会受到…

微信开发之 二维码生成类库

最近weiphp 二次开真的有点累&#xff0c;漏洞百出。代码维护代价有点高。 <?php /*** Created by PhpStorm.* User: bin* Date: 15-1-16* Time: 上午9:48*/ namespace Home\Common;// 微信处理类 set_time_limit(30); class Weixin{//构造方法static $qrcode_url "h…

通过Matlab实现离散序列卷积和

前言 年轻人&#xff0c;你对数学一无所知&#xff0c;你只是习惯了而已。—冯诺伊曼 Young man, in mathematics you dont understand things. You just get used to them.—John von Neumann。 一、卷积和是什么&#xff1f; 卷积的本质是描述一个瞬时动作&#xff08;激励…

Ansible 五(inventory文件 主机清单)

Ansible 五&#xff08;inventory文件 主机清单&#xff09;Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置. 默认的文件路径为 /etc/ansible/hosts除默认文件外,你还可以同时使用多个 inventory 文件(后面会讲到),也可以从动态源,或云上…

python series用法_如何使用Python中的Series字典创建数据框?

数据框是一种二维数据结构&#xff0c;其中数据以表格格式存储&#xff0c;以行和列的形式。它可以可视化为SQL数据表或excel工作表表示形式。可以使用以下构造函数创建它-pd.Dataframe(data, index, columns, dtype, copy)让我们了解如何使用Series字典创建数据框。系列是“熊…

[转载]android设置全屏和无标题

先介绍去掉标题栏的方法&#xff1a; 第一种&#xff1a;也一般入门的时候经常使用的一种方法 requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏注意这句一定要写在setContentView()方法的前面&#xff0c;不然会报错的 第二种&#xff1a;在AndroidManifest.xml文…

mac电脑下Tomcat和Apach配置流程(超详细)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 本章介绍在mac 电脑下如何配置Tomcat、Apach等环境 一、Apache介绍及配置 1.XAMPP安装 为了更好的进行各项软件服务的配置&#xff0c;引入快捷脚本工具——XMAPP。…

MVC 分页

后台代码: using Webdiyer.WebControls.Mvc; 1 public ActionResult Index(int id 1)2 {3 int pageIndex id;4 int count;5 int pageSize 7;6 7 List<News> newsList 8 newsSer.QueryByPage…

cvc 降噪_耳机降噪功能这么多,说说什么是ANC、ENC、CVC、DSP降噪

降噪功能对耳机的作用很重要&#xff0c;一是减少噪音&#xff0c;避免过度放大音量&#xff0c;从而减少对耳朵的损害。二是过滤噪音从而提高音质和通话质量。降噪可分为被动式降噪和主动式降噪。被动式降噪也就是物理降噪&#xff0c;被动式降噪是指利用物理特性将外部噪声与…

RPC 和 RESTful

2019独角兽企业重金招聘Python工程师标准>>> to do ... 转载于:https://my.oschina.net/u/2002769/blog/1505410

[linx] ubuntu网络重启命令

/etc/init.d/networking restart #这种方式必须有/etc/network/interface文件 ifconfig eth0 down #直接重启网卡 ifconfig eth0 up 转载于:https://www.cnblogs.com/fantasy01/p/4229734.html

密码学入门1——凯撒密码和三重DES加解密

实验目的 1、完成第一个入门加解密——凯撒密码 2、完成当下较为流行的三重DES加解密技术 3、熟悉所学的实际运用方向 实验准备 硬件&#xff1a;计算机或笔记本电脑 操作系统&#xff1a;Mac操作系统 IDE环境&#xff1a;Eclipse 程序语言&#xff1a;Java 一、实验基本…

老李谈JVM内存模型

老李谈JVM内存模型 poptest是国内唯一一家培养测试开发工程师的培训机构&#xff0c;以学员能胜任自动化测试&#xff0c;性能测试&#xff0c;测试工具开发等工作为目标。如果对课程感兴趣&#xff0c;请大家咨询qq&#xff1a;908821478&#xff0c;咨询电话010-84505200。 J…

emqx 使用端口_数据传输、存储、展现,EMQ X + TDengine 搭建 MQTT 物联网数据可视化平台...

物联网数据采集涉及到大量设备接入、海量的时序数据传输&#xff0c;EMQ X 消息中间件与 TDengine 大数据平台的组合技术栈完全能够胜任场景中的海量时间序列监测数据的传输、存储和计算。数据入库后&#xff0c;往往需要其他方式如数据可视化系统将数据按照规则统计、展现出来…

站点CSS样式不起作用,或仅仅有一部分起作用?随手记

事件&#xff1a;网页中使用了相同的样式&#xff0c;下半部分正常显示&#xff0c;上半部分样式所有丢失不能显示。解决&#xff1a;改动了相应的CSS样式文件的编码 这个是最没有想到的解决的方法。怎样调试&#xff1a;通过右键页面查看编码为UTF-8 或 GBK 看到样式正常显示&…