from oyanglul.usjavascript
Javascript 的测试, 无论在用 jasmine 仍是 mocha,
都是很头疼的事情. 可是自从有了 jest, 一口气写7个测试, 腰也不疼了, 头也不疼了.java
只须要 3 个理由jquery
在说用 jest 测为何好以前,咱们先来看咱们要测的一个例子.git
好比我要写一个模块要去取github 用户的follower 和他全部 repo 的 follower 数量.github
那么咱们应该有一个 User 的 Model.ajax
// user.js var $ = require('jquery'); function User(name) { this.name = name; this.followers = 0; } User.prototype.fetch = function(){ return $.ajax({ url: 'https://api.github.com/users/' + this.name, method: 'get', dataType: 'json' }).then(function(data){ this.followers = data.followers; }.bind(this)); }; module.exports = User;
咱们还须要一个 repo 的 model, 大同小异略去json
最后, 整合这俩我要的东西, 并显示在页面上api
// follower.js var $ = require('jquery'); function followerOf(user, repo) { user.fetch().then(repo.fetch).then(function(_){ $('#content').text(user.name +"'s followers: " + user.followers + " and his repo "+ repo.name +"'s followers:" + repo.followers); }); }; module.exports = followerOf;
--promise
自动 mock 实在是最大的亮点, jest 重写了 require, 因此你的代码里的全部 require 来的东西都自动 mock.dom
由于在你的测试中每每只关心一个模块, 对于他的全部依赖其实都是无所谓的.
在例子中, 若是咱们在测 repo.js 的时候彻底不关心那两个 jquery 的 ajax 方法到底
写对没写对,反正咱们指望能从 ajax 里面拿到咱们想要的东西就对了. 所以, 我但愿 jquery 的
全部方法都是 mock 的. jest 让你很轻松的作到这点, 由于是自动mock全部require 的东西, 而
对于目标测试模块, 只须要说我dontMock
个人目标模块就行了.
jest.dontMock('../repo'); describe('Repo Model', function(){ var repo; beforeEach(function(){ var $ = require('jquery').setAjaxReturn({stargazers_count: 23}); var Repo = require('../repo'); repo = new Repo('jcouyang', 'gira'); }); it('should populate properties with data from github api', function(){ repo.fetch(); expect(repo.followers).toBe(23); }); });
因此这个测试看起来就跟文档同样了,
dontMock('./repo')
说明我关心repo
你可能要问
segAjaxReturn
是哪里冒出来的. 忍一忍稍后告诉你.
有没有看虽然我显式的 mock jquery, 可是 Repo 里面 require 的 jquery 实际上是假的, 否则咱们就真的访问
github api 了. 那样就不会每次都返回 23 个 follower 了.
好了如今咱们来测 follower.js, 先看 follower 到底干了什么, 拿到 user 和 repo
的信息而后组成一句话放到页面 id 为 content 的元素下面.
好, 因此咱们关心
- 组出来的话对不对
- 有没有放到 content 元素下, 因此 jquery 的操做对不对也是咱们关心的一部分
咱们不关心
- user 干了什么
- repo 干了什么
这样,关心的就是不能 mock 的
jest.dontMock('../follower') .dontMock('jquery'); describe('follower', function(){ var user, repo, follower; var $ = require('jquery'); beforeEach(function(){ var Repo = require('../repo'); var User = require('../user'); follower = require('../follower'); user = new User('jcouyang'); repo = new Repo('jcouyang', 'gira'); // 咱们不关心 user, 可是咱们但愿他能返回一个 deferred 类型 user.fetch.mockReturnValue($.Deferred().resolve('dont care')); // 咱们让咱们不关心的 user 和 repo 返回咱们指望的东西就好 user.name ='jcouyang'; user.followers = 20; repo.name = 'gira'; repo.followers = 21; // 期待页面上有一个 id 为 content 的元素 document.body.innerHTML = ' <div id="content"></div> '; }); it('should populate properties with data from github api', function(){ follower(user,repo); // 但愿 content 上能获得想要的内容 expect($("#content").text()).toBe('jcouyang\'s followers: 20 and his repo gira\'s followers:21'); }); });
好了, 说好的解释 setAjaxReturn
是怎么回事的
嗯嗯, 是这样的, 虽然 jest 自动 mock 了咱们不关心的模块, 可是咱们仍是会但愿
这个 mock 的玩意能有一些咱们指望的行为, 也就是按咱们的指望返回一些东西. 好比
这里就是咱们不关心 ajax 的逻辑, 可是咱们须要他能给咱们返回一个东西,而且能够
thenable. 因此单纯的 mock 对象或函数都不能作到, 因此有了 manual mock 这种东西.
用 manual mock 须要建一个__ mocks__
文件夹,而后把全部的 mock 都扔进去. 好比
我想 mock jquery, 那么我建一个jquery.js
扔进去
var data = {}; var mockDefered = function(data){ return { then: function(cb){ return mockDefered(cb(data)); } }; }; function ajax() { return mockDefered(data); } function setAjaxReturn(shouldbe){ data = shouldbe; } exports.setAjaxReturn = setAjaxReturn; exports.ajax = ajax;
终于看见setAjaxReturn
在哪里定义了:sweat_smile: 这里暴露两个函数
- setAjaxReturn: 能够设置我但愿 ajax 返回的值
- ajax: 单纯的返回这个 thenable.
因此我也不须要显示的声明 mock jquery什么什么的, 直接在测试里设置ajax 的返回值就行了.
var $ = require('jquery').setAjaxReturn({stargazers_count: 23});
这是 repo 里面 require 的 jquery 已经被 mock 而且只要掉 ajax 都会返回我
指望的值.
pit('should populate properties with data from github api', function(){ return repo.fetch().then( expect(repo.followers).toBe(23); ); });
setTimeout(function() { callback(); }, 1000); expect(callback).not.toBeCalled(); jest.runAllTimers(); expect(callback).toBeCalled()
因此说白了, jest 其实也是个概念, 推荐使用模块化的思想, 这样我只须要保证每一个接口的 IO 正确, 就能够保证整个程序没问题. 这样划分下来测试就会变得简单到只须要关心固然模块的 IO 从而 能够 mock 掉全部其余依赖. 真正模块化好的代码单纯的只用 jasmine 或者 mocha 都应该是很好测的. 只是在这个概念之上省去了不少没必要要的 mock 代码, 由于要 mock 的 依赖老是占大多数的, 而关心的, 每每只是那么一两个.