Jest入門文檔

前端測試 Jest (未完待續)

1 配置環境

  1. node npm install --save-dev jest 需在環境變量中配置
  2. yarn yarn add --dev jest yarn global add jest

2 demo

jest 的工程文件後綴都是xx.test.js,咱們在運行一個jest工程的時候,jest會自動查找運行的後綴爲*.test.js的腳本進行單元測試。前端

machers 衆多的匹配判斷器

  1. toBe() 用於檢驗基本數據類型的值是否相等
  2. toEqual() 用於檢驗引用數據類型的值,因爲js自己object數據類型的自己特性,引用數據類型對比只是指針的對比,可是須要對比對象的每一個值,因此這時候用到的是toEqual()
  3. Truthiness 布爾值判斷的匹配器
  • toBeNull 只匹配 null
  • toBeUndefined 只匹配 undefined
  • toBeDefined 與 toBeUndefined 相反
  • toBeTruthy 匹配任何 if 語句爲真
  • toBeFalsy 匹配任何 if 語句爲假
  1. 數字匹配器 用於判斷數字值之間的對比
  • toBeGreaterThan 大於匹配器
  • toBeGreaterThanOrEqual 大於等於匹配器
  • toBeLessThan 小於匹配器
  • toBeLessThanOrEqual 小於等於匹配器
  • tobe 和 toequal 都是等價功能相同的對於數字
  1. toMatch 字符串匹配器 和字符串的match相同
  2. toContain 數組匹配器 用於判斷數組中是否包含某些值
  3. toThrow 報錯匹配器 用於測試特定的拋出錯誤,能夠判斷報錯語句的文字(支持正則匹配),也能夠判斷報錯類型。

異步代碼的判斷

js 基於單線程異步的特性,在代碼中充斥的異步程序和各類回調,因此咱們在測試異步代碼的時候要格外注意。一下是各類異步的案例node

  1. callback 回調
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});
 // 這種狀況有問題,你們都知道一個ajax請求是一個事件(由兩個事務發送和返回組成),當發送成功和返回成功這個事件就是完成的,就是成功的,這個時候jest就認爲ajax事件完成了,因此檢驗會在回調判斷執行前結束,沒有驗證data數據,因此這是有問題的。
複製代碼

Jest 提供了相應的方法來done來解決這樣的問題,確保回調執行的來完成整個test驗證。 使用單個參數調用 done,而不是將測試放在一個空參數的函數。Jest會等done回調函數執行結束後,結束測試。 let's show codeajax

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});
  若是 done()永遠不會調用,這個測試將失敗,這也是你所但願發生的。
複製代碼
  1. Promise 代碼使用Promise處理異步程序的話,咱們有更簡單的方法進行異步測試。若是Promise返回的狀態是reject則測試自動失敗。
test('Promise test', ()=>{
        // 斷言測試
        expect.assertions(1);
        // 必定記得return,不然測試拿不到promise的狀態,測試會在fetchData()完成前完成。
        return fetchData().then(data=>{
            expect(data).tobe('promise')
        })
    })
複製代碼

若是指望的promise是reject,咱們能夠經過catch來捕獲咱們的錯誤。 請確保添加 expect.assertions 來驗證必定數量的斷言被調用。 不然一個fulfilled態的 Promise 不會讓測試失敗。npm

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});
複製代碼
  1. .resolves / .rejects 匹配器 Jest有特殊的處理promise的匹配器,resolves和rejects。使用resolves匹配器處理promise,若是返回的狀態是reject則測試將自動失敗。切記不要丟失return。同理,你用rejects匹配器處理,若是你想獲得promise返回是reject可是promise成功了返回一個成功的狀態resolve(fulfilled),則測試結果是失敗的。
// let's show code~ // resolves test('the data is peanut butter', () => { expect.assertions(1); return expect(fetchData()).resolves.toBe('peanut butter'); }); // rejects test('the fetch fails with an error', () => { expect.assertions(1); return expect(fetchData()).rejects.toMatch('error'); }); 複製代碼
  1. Async/Await 你也可使用async/await 處理異步測試。只須要在test的回調函數前面添加async關鍵字。
// 提早了解async和await的使用方法和場景

test('the data is peanut butter', async () => {
  // 切記添加斷言測試
  expect.assertions(1);
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  // 切記添加斷言測試
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});
複製代碼

還能夠混合使用.resolves / .rejects和Async/Await編程

// 由於await自己返回的就是一個promise。因此咱們能夠在返回的promise的基礎之上繼續測試咱們的代碼。
test('the data is peanut butter', async () => {
  expect.assertions(1);
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  await expect(fetchData()).rejects.toMatch('error');
});
複製代碼

#Jest的遍歷 和 Setup 和 Teardown 進行一些重複的test設置的時候,咱們可使用beforeEach和afterEach。假設咱們在一個交互數據上須要重複的作一些測試設置。假如測試前調用initializeCityDatabase()和測試後調用clearCityDatabase()。那咱們就可使用beforeEach和afterEach了。 let's show code~數組

beforeEach and afterEach

beforeEach(() => {
      initializeCityDatabase();
    });
    
    afterEach(() => {
      clearCityDatabase();
    });
    
    test('city database has Vienna', () => {
      expect(isCity('Vienna')).toBeTruthy();
    });
    
    test('city database has San Juan', () => {
      expect(isCity('San Juan')).toBeTruthy();
    });
複製代碼

beforeEach 和 afterEach處理異步的代碼,一樣能夠採用done和promise,若是initializeCityDatabase()返回的是一個promise咱們能夠這樣處理他。let's show codepromise

beforeEach(()=>{
        return initializeCityDatabase(); // return一個promise
    })
複製代碼

beforeAll and afterAll

Scoping

咱們能夠經過Jest的describe函數,經過js函數式編程的思想來建立一個做用域,來模塊化咱們的測試。具體場景就是的經過describe來模塊咱們的foreach的做用範圍。 let's show codebash

// 這裏的beforeEach適用於全部的test
beforeEach(() => {
  return initializeCityDatabase();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

describe('matching cities to foods', () => {
  // 這裏beforeEach僅僅適用於describe中的測試
  beforeEach(() => {
    return initializeFoodDatabase();
  });

  test('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
  });

  test('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});
複製代碼

既然這麼多beforeEach/afterEach和beforeAll/afterAll,那結合descibe來看看咱們的執行順序。相信你們看完之後會想起js的(任務隊列和做用域)。異步

beforeAll(() => console.log('1 - beforeAll'));
    afterAll(() => console.log('1 - afterAll'));
    beforeEach(() => console.log('1 - beforeEach'));
    afterEach(() => console.log('1 - afterEach'));
    test('', () => console.log('1 - test'));
    describe('Scoped / Nested block', () => {
      beforeAll(() => console.log('2 - beforeAll'));
      afterAll(() => console.log('2 - afterAll'));
      beforeEach(() => console.log('2 - beforeEach'));
      afterEach(() => console.log('2 - afterEach'));
      test('', () => console.log('2 - test'));
    });
    
    // 1 - beforeAll
    // 1 - beforeEach
    // 1 - test
    // 1 - afterEach
    // 2 - beforeAll
    // 1 - beforeEach
    // 2 - beforeEach
    // 2 - test
    // 2 - afterEach
    // 1 - afterEach
    // 2 - afterAll
    // 1 - afterAll
    
正如結果查看順序,全局的會做用到describe內部。 注意執行順序,beforeALL和afterAll只會執行一次, 全局的beforeEach做用到了describe中的test,還要注意的是after做用域中的after比全局的after先執行。
beforeAll 在beforeEach前先執行,而afterAll在afterEach後執行。
複製代碼

若是你想在衆多的test中,僅僅想進行其中的一個test,很簡單,你只要在他的test語句中添加.only標識就能夠了,其餘的測試則會跳過了.let's show codeasync

// 只有這個test會跑
test.only('this will be the only test that runs', () => {
  expect(true).toBe(false);
});

// 這個test則會跳過
test('this test will not run', () => {
  expect('A').toBe('A');
});
複製代碼
相關文章
相關標籤/搜索