前端測試框架Jest系列教程 -- Asynchronous(測試異步代碼)


寫在前面:

  在JavaScript代碼中,異步運行是很常見的。當你有異步運行的代碼時,Jest需要知道它測試的代碼何時完成,然后才能繼續進行另一個測試。Jest提供了幾種方法來處理這個問題。

測試異步代碼的三種實現方式:

方法一:回調函數

這是非常常見的通用處理方式,比如你有一個fetchData(callback)的function用來獲取數據,並且在獲取完成的時候調用callback 函數,你想測試返回的數據是“peanut butter” ,默認情況下當fetchData執行完成的時候Jest的測試就完成了,這並不是你所期望的那樣的去運行。

// Don't do this!
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});

上面代碼的問題就在於一旦fetchData完成,測試也就執行完成,然后再調用回調。

Jest提供了一種用於測試的實現方式,下面代碼 done() 被執行則意味着callback函數被調用。 

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

  fetchData(callback);
});

如果 done 永遠都不被調用,那么的測試將會失敗,這也正是我們期望的(我們希望callback被調用,並且返回的data是我們期望的值)

方法二:承諾驗證

如果你的代碼中使用了承諾的方式,處理異步測試將會變得更加簡單。Jest從你的測試中返回一個承諾,然后等待承諾被實現,如果沒有實現,那么就判斷測試是失敗的。

還是上面的例子,如果用承諾驗證,那么實現將是下面的樣子:

test('the data is peanut butter', () => {
  expect.assertions(1);
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

assertions(1)代表的是在當前的測試中至少有一個斷言是被調用的,否則判定為失敗。

如果刪掉return語句,那么你的測試將在fetchData完成之前結束。

如果斷言的承諾並沒有被實現,那么你可以添加 .catch 方法。一定要添加expect,斷言驗證一定數量的斷言被調用。否則一個實現的承諾就不會失敗。

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});

在Jest 20.0.0+  的版本中你可以使用 .resolves 匹配器在你的expect語句中,Jest將會等待一直到承諾被實現,如果承諾沒有被實現,測試將自動失敗。

test('the data is peanut butter', () => {
  expect.assertions(1);
  return expect(fetchData()).resolves.toBe('peanut butter');
});

如果你期望你的承諾是不被實現的,你可以使用 .rejects ,它的原理和 .resolves類似

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return expect(fetchData()).rejects.toMatch('error');
});

第三種:使用 Async/Await

我相信大家最Async/Await 是比較熟悉的,你可以在測試中使用異步和等待。要編寫一個async測試,只需在傳遞到測試的函數前面使用async關鍵字。例如上面同樣的fetchData場景可以使用下面的實現:

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');
  }
});

當然你也可以將Async Await和 .resolves  .rejects 結合起來(Jest 20.0.0+  的版本)

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');
});

寫在最后:

在這些情況下,異步和等待實際上只是與承諾示例使用的相同邏輯的語法糖。


這幾種方法中沒有一個特別優於另外一個,你可以將它們組合在一個代碼庫中,甚至可以在單個文件中進行匹配。它只是取決於哪種樣式使你的測試更簡單。

 

系列教程:

   1. 前端測試框架Jest系列教程 -- Matchers(匹配器)

   2.前端測試框架Jest系列教程 -- Asynchronous(測試異步代碼)

   3.前端測試框架Jest系列教程 -- Mock Functions(模擬器)

   4.前端測試框架Jest系列教程 -- Global Functions(全局函數)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM