React 16 Jest手動(dòng)模擬(Manual Mocks)

React 16 Jest手動(dòng)模擬(Manual Mocks)

項(xiàng)目初始化

git clone https://github.com/durban89/webpack4-react16-reactrouter-demo.git 
cd webpack4-react16-reactrouter-demo
git fetch origin
git checkout v_1.0.27
npm install

手動(dòng)模擬(Manual Mocks)

手動(dòng)模擬主要功能是用于存儲(chǔ)模擬的數(shù)據(jù)。

例如,我可能希望創(chuàng)建一個(gè)允許您使用虛假數(shù)據(jù)的手動(dòng)模擬,而不是訪問網(wǎng)站或數(shù)據(jù)庫(kù)等遠(yuǎn)程資源。

這可以確保您的測(cè)試快速且不易碎(not flaky)。

模擬水果模塊(Mocking fruit modules)

通過在緊鄰模塊的mocks/子目錄中編寫模塊來定義手動(dòng)模擬。這個(gè)方式我在前面文章中的實(shí)例中也有用到過,具體的可以參考之前的文章,這里我說下大概的流程

例如,要在src/lib目錄中模擬一個(gè)名為fruit的模塊,則分別創(chuàng)建文件src/lib/fruit.js和文件src/lib/mocks/fruit.js的文件。

請(qǐng)注意mocks文件夾區(qū)分大小寫。如果命名目錄是MOCKS,則可能在某些系統(tǒng)上測(cè)試的時(shí)候會(huì)中斷。

注意點(diǎn)

當(dāng)我們?cè)跍y(cè)試中需要該模塊時(shí),還需要顯式的調(diào)用jest.mock('./moduleName')。

模擬Node核心模塊(Mocking Node modules)

如果正在模擬的模塊是Node module(例如:lodash),則模擬應(yīng)放在與node_modules相鄰的mocks目錄中(除非您將根配置為指向項(xiàng)目根目錄以外的文件夾)并將自動(dòng)模擬。

沒有必要顯式調(diào)用jest.mock('module_name')。

可以通過在與范圍模塊的名稱匹配的目錄結(jié)構(gòu)中創(chuàng)建文件來模擬范圍模塊。

例如,要模擬名為@scope/project-name的作用域模塊,請(qǐng)?jiān)?strong>mocks/@scope/project-name.js創(chuàng)建一個(gè)文件,相應(yīng)地創(chuàng)建@scope/目錄。

注意點(diǎn)

如果我們想模擬Node的核心模塊(例如:fs或path),那么明確地調(diào)用。

例如:jest.mock('path')是必需的,因?yàn)槟J(rèn)情況下不會(huì)模擬核心Node模塊。

實(shí)例演示

當(dāng)給定模塊存在手動(dòng)模擬時(shí),Jest的模塊系統(tǒng)將在顯式調(diào)用jest.mock('moduleName')時(shí)使用該模塊。

但是,當(dāng)automock設(shè)置為true時(shí),即使未調(diào)用jest.mock('moduleName'),也將使用手動(dòng)模擬實(shí)現(xiàn)而不是自動(dòng)創(chuàng)建的模擬。

要選擇不使用此行為,您需要在應(yīng)使用實(shí)際模塊實(shí)現(xiàn)的測(cè)試中顯式調(diào)用jest.unmock('moduleName')。

注意點(diǎn)

為了正確模擬,Jest需要jest.mock('moduleName')與require/import語(yǔ)句在同一范圍內(nèi)。

假設(shè)我們有一個(gè)模塊,它提供給定目錄中所有文件的摘要。在這種情況下,我們使用核心(內(nèi)置)fs模塊來演示

src/lib/FileSummarizer.js

const fs = require('fs');

function summarizeFilesInDirectorySync(directory) {
  return fs.readdirSync(directory).map(fileName => ({
    directory,
    fileName,
  }));
}

exports.summarizeFilesInDirectorySync = summarizeFilesInDirectorySync;

由于我們希望我們的測(cè)試避免實(shí)際操作磁盤(這非常慢且易碎[fragile]),我們通過擴(kuò)展自動(dòng)模擬為fs模塊創(chuàng)建手動(dòng)模擬。

我們的手動(dòng)模擬將實(shí)現(xiàn)我們可以為我們的測(cè)試構(gòu)建的fs API的自定義版本:

src/lib/mocks/fs.js

const path = require('path');

const fs = jest.genMockFromModule('fs');

let mockFiles = Object.create(null);

function __setMockFiles(newMockFiles) {
  mockFiles = Object.create(null);

  const keys = Object.keys(newMockFiles);

  for (let index = 0; index < keys.length; index += 1) {
    const file = keys[index];
    const dir = path.dirname(file);
    if (!mockFiles[dir]) {
      mockFiles[dir] = [];
    }
    mockFiles[dir].push(path.basename(file));
  }
}

function readdirSync(directoryPath) {
  return mockFiles[directoryPath] || [];
}

fs.__setMockFiles = __setMockFiles;
fs.readdirSync = readdirSync;

module.exports = fs;

現(xiàn)在我們編寫測(cè)試。

請(qǐng)注意,我們需要明確告訴我們要模擬fs模塊,因?yàn)樗且粋€(gè)核心Node模塊:

src/tests/FileSummarizer-test.js

const fs = require('fs');
const FileSummarizer = require('../lib/FileSummarizer');

jest.mock('fs');

describe('listFilesInDirectorySync', () => {
  const MOCK_FILE_INFO = {
    '/path/to/file1.js': 'console.log("file1 contents");',
    '/path/to/file2.txt': 'file2 contents',
  };

  beforeEach(() => {
    // Set up some mocked out file info before each test
    fs.__setMockFiles(MOCK_FILE_INFO);
  });

  test('includes all files in the directory in the summary', () => {
    const fileSummary = FileSummarizer.summarizeFilesInDirectorySync('/path/to');

    expect(fileSummary.length).toBe(2);
  });
});

此處顯示的示例模擬使用jest.genMockFromModule生成自動(dòng)模擬,并覆蓋其默認(rèn)行為。

這是推薦的方法,但完全是可選的。

如果您根本不想使用自動(dòng)模擬,則只需從模擬文件中導(dǎo)出自己的函數(shù)即可。

完全手動(dòng)模擬的一個(gè)缺點(diǎn)是它們是手動(dòng)的 - 這意味著你必須在它們模擬的模塊發(fā)生變化時(shí)手動(dòng)更新它們。

因此,最好在滿足您的需求時(shí)使用或擴(kuò)展自動(dòng)模擬。

為了確保手動(dòng)模擬及其實(shí)際實(shí)現(xiàn)保持同步,在手動(dòng)模擬中使用require.requireActual(moduleName)并在導(dǎo)出之前使用模擬函數(shù)修改它可能是有用的。

項(xiàng)目實(shí)踐地址

https://github.com/durban89/webpack4-react16-reactrouter-demo.git
tag:v_1.0.28
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,238評(píng)論 0 1
  • 在現(xiàn)在的前端開發(fā)中,前后端分離、模塊化開發(fā)、版本控制、文件合并與壓縮、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,659評(píng)論 1 32
  • 一、介紹 Mocks可以捕獲對(duì)函數(shù)的調(diào)用(以下用法一)使用mock function,可以查看函數(shù)的調(diào)用次數(shù),以及...
    One_Hund閱讀 3,551評(píng)論 0 0
  • 有些事明知道結(jié)果,但還是會(huì)選擇去做。因?yàn)椴蝗プ?,還是會(huì)心有不甘,存在遺憾! 也不管最后結(jié)果是怎樣,抬頭,微笑,藍(lán)天...
    情書短句閱讀 354評(píng)論 0 0
  • 窗外不停的雨,依著卷簾的你。 撐一把雨傘,著一身夏衣。 聽落下的聲音,看蕩出的漣漪。 你太調(diào)皮,畫遍了我的足跡。 ...
    濟(jì)夏閱讀 578評(píng)論 0 49

友情鏈接更多精彩內(nèi)容