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 的 依賴老是佔大多數的, 而關心的, 每每只是那麼一兩個.