對(duì)VS Code extension進(jìn)行單元測(cè)試時(shí)通常會(huì)遇到一個(gè)問題,代碼中所使用的VS Code編輯器的功能都依賴于vscode庫,但是我們?cè)趩卧獪y(cè)試中并沒有添加對(duì)vscode庫的依賴,所以導(dǎo)致運(yùn)行單元測(cè)試時(shí)出錯(cuò)。由于vscode庫是作為第三方依賴被引入到我們的VS Code extension中的,所以它并不受我們的控制,最好的辦法就是在單元測(cè)試中對(duì)其中的API進(jìn)行模擬。本文中我將介紹如何使用Jest來模擬vscode庫的API。
如果你還不太熟悉如何開始創(chuàng)建一個(gè)VS Code extension,這里的文檔可以教你快速上手。
創(chuàng)建好VS Code extension項(xiàng)目后,你會(huì)發(fā)現(xiàn)在根目錄下有一個(gè)package.json文件,VS Code extension會(huì)從中讀取配置項(xiàng)來管理UI界面元素,在實(shí)際開發(fā)中你可能會(huì)使用到其中的一些屬性。我們可以通過package.json來設(shè)置項(xiàng)目所需要的依賴項(xiàng),這里我們將Jest添加為dev dependency,并添加npm腳本以運(yùn)行Jest單元測(cè)試。
npm i -D jest
{ "scripts": { "test": "jest" } }
模擬VS Code node module
Jest提供了一些mocking的選項(xiàng),但是因?yàn)槲覀兿胍M整個(gè)vscode node module,所以最簡單的辦法是在與node_modules文件夾相同的位置(通常是項(xiàng)目的根目錄)創(chuàng)建一個(gè)__mocks__文件夾,并在其中添加一個(gè)與要模擬的模塊名稱相同的文件(vscode.js)。
你不需要在測(cè)試代碼中導(dǎo)入該模塊,mock會(huì)自動(dòng)加載它。Jest稱此為manual mocks。
這種方法最大的好處是它能將我們的測(cè)試代碼與所依賴的模塊分離,使測(cè)試代碼看起來更加整潔。這里有一個(gè)小問題,新加入的開發(fā)者需要知道__mocks__文件夾,否則很難理解單元測(cè)試是如何正常工作的,因?yàn)閱卧獪y(cè)試中并沒有VS Code模塊被模擬的代碼。
以下就是對(duì)VS Code模塊進(jìn)行模擬的代碼。我們并沒有模擬整個(gè)API,你可以根據(jù)需要進(jìn)行調(diào)整。
// vscode.js const languages = { createDiagnosticCollection: jest.fn() }; const StatusBarAlignment = {}; const window = { createStatusBarItem: jest.fn(() => ({ show: jest.fn() })), showErrorMessage: jest.fn(), showWarningMessage: jest.fn(), createTextEditorDecorationType: jest.fn() }; const workspace = { getConfiguration: jest.fn(), workspaceFolders: [], onDidSaveTextDocument: jest.fn() }; const OverviewRulerLane = { Left: null }; const Uri = { file: f => f, parse: jest.fn() }; const Range = jest.fn(); const Diagnostic = jest.fn(); const DiagnosticSeverity = { Error: 0, Warning: 1, Information: 2, Hint: 3 }; const debug = { onDidTerminateDebugSession: jest.fn(), startDebugging: jest.fn() }; const commands = { executeCommand: jest.fn() }; const vscode = { languages, StatusBarAlignment, window, workspace, OverviewRulerLane, Uri, Range, Diagnostic, DiagnosticSeverity, debug, commands }; module.exports = vscode;
使用模擬的VS Code模塊的示例
我的開源項(xiàng)目Git Mob for VS code中使用了這種方法,我將用其中的代碼來說明如何使用模擬的VS Code模塊。
下面的例子中,VS Code編輯器的狀態(tài)欄會(huì)根據(jù)Git鉤子prepare-commit-msg是否被調(diào)用來做相應(yīng)的調(diào)整,你可以看到這里我并沒有將vscode模塊導(dǎo)入到我的測(cè)試文件中并對(duì)其進(jìn)行模擬。
// git-mob-hook-status.spec.js const { hasPrepareCommitMsgTemplate } = require("../prepare-commit-msg-file"); const { gitMobHookStatus } = require("./git-mob-hook-status"); jest.mock("./../prepare-commit-msg-file"); describe("Hook or template status", function() { let mockContext; beforeAll(function() { mockContext = { subscriptions: [] }; }); afterEach(function() { hasPrepareCommitMsgTemplate.mockReset(); }); it("using git template for co-authors", () => { hasPrepareCommitMsgTemplate.mockReturnValue(false); const statusBar = gitMobHookStatus({ context: mockContext })(); expect(statusBar).toEqual( expect.objectContaining({ text: "$(file-code) Git Mob", tooltip: "Using .gitmessage template" }) ); }); it("using git prepare commit msg for co-authors", () => { hasPrepareCommitMsgTemplate.mockReturnValue(true); const statusBar = gitMobHookStatus({ context: mockContext })(); expect(statusBar).toEqual( expect.objectContaining({ text: "$(zap) Git Mob", tooltip: "Using prepare-commit-msg hook" }) ); }); });
// git-mob-hook-status.js const vscode = require("vscode"); const { hasPrepareCommitMsgTemplate } = require("../prepare-commit-msg-file"); function gitMobHookStatus({ context }) { const myStatusBarItem = vscode.window.createStatusBarItem( vscode.StatusBarAlignment.Left, 10 ); context.subscriptions.push(myStatusBarItem); return function() { myStatusBarItem.text = "$(file-code) Git Mob"; myStatusBarItem.tooltip = "Using .gitmessage template"; if (hasPrepareCommitMsgTemplate()) { myStatusBarItem.text = "$(zap) Git Mob"; myStatusBarItem.tooltip = "Using prepare-commit-msg hook"; } myStatusBarItem.show(); return myStatusBarItem; }; } exports.gitMobHookStatus = gitMobHookStatus;
你可以在這里查看源代碼:
- git-mob-hook-status.spec.js
- git-mob-hook-status.js
我能檢查vscode模塊中的方法是否被調(diào)用了嗎?
你可以導(dǎo)入模擬的vscode模塊。下面的代碼中,我想要檢查當(dāng)用戶修改co-author文件時(shí)onDidSaveTextDocument事件是否被訂閱了。
const vscode = require("../__mocks__/vscode"); // ... test("Reload co-author list when git-coauthors file saved", () => { reloadOnSave(coAuthorProviderStub); expect(vscode.workspace.onDidSaveTextDocument).toHaveBeenCalledWith( expect.any(Function) ); // ... }); // ...
可以看到這里都是Jest mock API的標(biāo)準(zhǔn)用法,這意味著我們可以在代碼中正常使用vscode模塊的方法,而不受manual mock的任何限制。例如,我們還可以使用mockImplementation來修改實(shí)現(xiàn)。
更多示例可以查看這里的源代碼:
- reload-on-save.spec.js
編寫單元測(cè)試最大的好處是可以快速得到反饋結(jié)果,如果你對(duì)TDD(Test-Driven Development,測(cè)試驅(qū)動(dòng)開發(fā))情有獨(dú)鐘,那么單元測(cè)試將使你對(duì)VS Code extension的開發(fā)更加信心滿滿。文章來源:http://www.zghlxwxcb.cn/news/detail-634740.html
原文地址:Unit test & mock VS Code extension API with Jest文章來源地址http://www.zghlxwxcb.cn/news/detail-634740.html
到了這里,關(guān)于在單元測(cè)試中使用Jest模擬VS Code extension API的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!