前端單元測試

單元測試

前端測試框架主要是Mocha與Jasmine,這里我們選擇Mocha,斷言庫有should、expect、chai以及node自帶的assert。這里我們選擇chai,chai中包含了expect、should及assert的書寫風格。

關于構建這一塊給大家推薦一篇:前端測試環境搭建;


  • 這里我們重點介紹 mocha 和 chai 的語法和用法

  • 如果安裝過程中報錯,嘗試清除下node_modules重新安裝依賴 (mac下可能會報一些錯 不過問題不大 ~~)

mocha

  • 基本用法 (這里默認大家搭建好了環境 直接上代碼~~)

 const getNum = (value) => {
   if(value === 0) {
     return 1
   }else {
     return value * 2
   }
 }

describe('Test', function() {
  it('should return 20 when the value is 10', function() {
      expect(getNum(10)).to.equal(20)
  })

  it('should return 1 when the value is 0', function() {
    expect(getNum(0)).to.equal(0)
  })
})


  • 鉤子函數

 before(function () {
    createDiv('test')
  })

  beforeEach(function() {   
    
    console.log('即將測試 ^_^');     
  })

  afterEach(function() {
    console.log('測試結束 準備下一個測試 ^_^');
  })

  after(function() {
    console.log('Tests所有測試結束 ^_^');
  })


  • 幾個常用的方法介紹

//only

  it.only('only run this',function() {
    // setTimeout(done, 300);  //來判定是否超時
    console.log('只會執行這個');    // only 方法  可以給多個子例綁定only 方法
  })
})


//skip 和 retries

 it.skip('i will skip ',function() {
    console.log('可以不用注釋這段代碼哦')  // skip方法用于跳過指定用例

  })

  it.only('如果不滿足條件 我就跳過這個用例',function() {
    // setTimeout(done, 300);
    this.retries(2);    // 失敗后 繼續執行 2次
  //    console.log('繼續嘗試測試 執行中...')
    if(false) {
        console.log('條件滿足 正常測試')
    }else{
        this.skip();   // 跳過該測試
    }
  })


//timeout

 beforeEach(function(done) {     //如果這段代碼很耗時 下面的測試也會影響到    如果不想引入 done參數也要去掉
    // this.timeout(3000); // A very long environment setup.
    //setTimeout(done, 2500);
    console.log('即將測試 ^_^');     
  })




//循環任務
function add() {
  return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
    return prev + curr;
  }, 0);
}

describe('add()', function() {

 after(function() {
    console.log('ADD所有測試結束 ^_^');
  })

  var tests = [
    {args: [1, 2],       expected: 3},
    {args: [1, 2, 3],    expected: 6},
    {args: [1, 2, 3, 4], expected: 10}
  ];

  tests.forEach(function(test) {
    it.only('correctly adds ' + test.args.length + ' args', function() {   // 如果前面的測試單元用了only方法這里也是不會被測試到的 所以也要加only
      var res = add.apply(null, test.args);
       expect(res).to.equal(test.expected)
    });
  });
});


const qual = function(val) {
    return val*2;
}


chai

  • 以下是chai常用的一些斷言語法

// not 
it.only("鏈式",function() {
        expect(qual(10)).to.equal(20);  // 肯定
        expect(qual(11)).to.not.equal(20);  //取反
    });


// any 和 all
let foos = {bar:'baz',baz:'baa'};
expect(foos).to.have.any.keys('bar','baz');   // any  期望有一個這樣 key鍵
expect(foos).to.have.all.keys('bar','baz');  // all  期望全部都是


 // a  或an  測試值類型
    expect('test').to.be.a('string');
    expect(foos).to.be.an('object');
    expect(null).to.be.a('null');
    expect(undefined).to.be.a('undefined');
    expect(new Error).to.be.an('error');


  //include 包含斷言
    expect([1,2,3]).to.include(2);
    expect({a:1,b:2}).to.include.keys('a');


    //ok 斷言目標為真
    expect('1').to.be.ok;

    //true  不會對類型進行轉換
    expect('1').to.be.not.true;

    //false  不會對類型進行轉換
    expect('1').to.be.not.false;

    //null undefined  
    expect(null).to.be.null;
    expect(undefined).to.undefined;

    //NAN
    expect('1').to.be.NAN;

    //exist  非null 非undefined
    let c = null,d = 1;
    expect(c).to.be.not.exist;
    expect(d).to.be.exist;

    //empty 判斷目標長度 為空 length
    expect({c:1}).to.not.empty;

    //arguments
    function test1() {
      expect(arguments).to.arguments;
    }

    //equal(value)  嚴格等于

    expect(1+1).to.equal(2);
    expect({foo:'a'}).to.not.equal({foo:'a'});  // 不嚴格等于  對象地址不同
    expect({foo:'a'}).to.deep.equal({foo:'a'});  // 帶有deep標記的  比較的是實際的value

    //eql(value)  相當于深度比較
    expect({foo:'a'}).to.eql({foo:'a'});


    //above 大于
    expect(3).to.above(1);
    //可以配合length使用
    expect('hahha').to.have.length.above(1);

    //least 大于等于
    expect(2).to.least(2);

    //below 小于
    expect(2).to.below(4);

    //most 小于等于
    expect(4).to.most(5);

    //within  測試區間內
    expect(4).to.within(1,6);


    let inst = function() {} , inst_ = new inst();

    //instanceof(constructor)  判斷實例是否屬于構造函數
    expect(inst_).to.instanceof(inst);


    //property(name,value)
    expect({foo:'baz'}).to.have.property('foo','baz');


    //ownProperty(name)  判斷自身屬性

    expect('strings').to.have.ownProperty('length');

    //.length


    //lengthOf(value)  期待的length值
    expect('111').to.have.lengthOf(3);


    //match(reg)  匹配正則
    expect('wahaha').to.match(/^wa/);


    //string(value)  判斷字符串包含另一個字符串
    expect('wahaha').to.have.string('haha');


    //keys



    //throw  斷言出錯
    var fn = function () { throw err }

    expect(fn).to.throw(ReferenceError);



    //respondTo(method)  斷言目標對象下有該方法

    inst.prototype.test = function() {};
    expect(inst).to.respondTo('test');
    //掛載itself方法   對象自身方法 而不是公共的
    expect(inst).itself.to.not.respondTo('test');



    //satisfy(fn)  給測試目標傳入函數  返回期望值
    expect(2).to.satisfy(function(num) { return num > 1 });


    //closeTo(expect,范圍)
    expect(1.5).to.closeTo(1,0.8);  //期望是1,但是只要在0.8范圍內就好


    //members(set)  斷言集合

    expect([1,2,3]).to.have.members([3,2,1]); 
    expect([1,2]).to.have.include.members([1]);


    //oneOf 斷言位置
    expect(1).to.oneOf([1,2,3]);


    //change(object, property)   斷言目標方法會改變指定對象的指定屬性
    let fn1 = { val:2 };
    let fn2 = function() {  fn1.val++; };


    expect(fn2).to.change(fn1,'val');   //期待fn2能夠改變fn1的屬性val的值


    //increase (object, property)  斷言目標方法會增加指定對象的屬性
    let fn3 = { val:2 };
    let fn4 = function() {  fn3.val++; };

    expect(fn4).to.increase(fn3,'val');




    // decrease(object, property)   斷言目標方法會減少指定對象的屬性
    let fn5 = function() {  fn3.val--; };
    expect(fn5).to.decrease(fn3,'val');

   // .extensible  斷言目標對象是可擴展的(可以添加新的屬性)    .sealed 封閉
    expect({}).to.be.extensible;



    //.frozen   斷言目標對象是凍結的(無法添加新的屬性并且存在的屬性不能被刪除和修改)
    var frozenObject = Object.freeze({})

    expect(frozenObject).to.be.frozen
    expect({}).to.not.be.frozen
 
    })
})



?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容