[gist]用 jest 轻松测试 JavaScript

from oyanglul.us

Javascript 的测试, 不论在用 jasmine 照样 mocha,
都是很头疼的事变. 然则自从有了 jest, 一口气写7个测试, 腰也不疼了, 头也不疼了.

只须要 3 个来由

在说用 jest 测为何好之前,我们先来看我们要测的一个例子.

栗子

比方我要写一个模块要去取github 用户的follower 和他一切 repo 的 follower 数目.

那末我们应该有一个 User 的 Model.

// 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, 迥然不同略去

末了, 整合这俩我要的东西, 并显如今页面上

// 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;

1. Auto Mock

自动 mock 实在是最大的亮点, jest 重写了 require, 所以你的代码里的一切 require 来的东西都自动 mock.

由于在你的测试中每每只体贴一个模块, 关于他的一切依靠实在都是无所谓的.

在例子中, 假如我们在测 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);
  });
});

所以这个测试看起来就跟文档一样了,

  1. dontMock('./repo') 申明我体贴repo
    这个模块, 其他我都不 care.
  2. before 是我要举行操纵所须要的东西.
    • 我要 jquery ajax 要求给我想要的数据
    • 我要一个我要测的 Repo 类的实例
  3. it 申明我体贴地行动是神马
    • 我体贴 fetch 的行动,是去取数据并给我把数据添补到我的 repo 实例中

你能够要问 segAjaxReturn 是那里冒出来的. 忍一忍稍后通知你.

有无看虽然我显式的 mock jquery, 然则 Repo 内里 require 的 jquery 实际上是假的, 不然我们就真的接见
github api 了. 那样就不会每次都返回 23 个 follower 了.

2. jsdom

好了如今我们来测 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');
  });
});

3. Manual Mock

好了, 说好的诠释 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 都邑返回我
希冀的值.

etc

  • 并行测试:
    还用说么, 既然已云云模块化好了, user repo 以及 follower 的测试完整是互不依靠.
    没有什么来由一个一个测. 因而3个测试的耗时取决于最长时候的谁人. 所以假如有
    谁人测试迥殊耗时,申明模块还不够细, 多拆几个就快了.
  • promise: 运用 pit() 来测试 thenable 的对象, 比方 repo 的例子,就 keyi
    写成
pit('should populate properties with data from github api', function(){
  return repo.fetch().then(
    expect(repo.followers).toBe(23);
  );
});
  • Timer mocks: 能够运用 mock 的 timer 和 ticks, 也就是你能够加快
    一切的setTimeout, setInterval, clearTimeout, clearInterval行动. 不须要守候.
setTimeout(function() { callback(); }, 1000);
 expect(callback).not.toBeCalled();
 jest.runAllTimers();
expect(callback).toBeCalled()

Wrapup

所以说白了, jest 实在也是个观点, 引荐运用模块化的头脑, 如许我只须要保证每一个接口的 IO 准确, 就能够保证全部顺序没问题. 如许分别下来测试就会变得简朴到只须要体贴固然模块的 IO 从而
能够 mock 掉一切其他依靠. 真正模块化好的代码纯真的只用 jasmine 或许 mocha
都应该是很好测的. 只是在这个观点之上省去了许多不必要的 mock 代码, 由于要 mock 的
依靠老是占大多数的, 而体贴的, 每每只是那末一两个.

    原文作者:oyanglulu
    原文地址: https://segmentfault.com/a/1190000000644658
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞