51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 398|回复: 0
打印 上一主题 下一主题

[转贴] 使用Jest模拟VS Code extension API之单元测试

[复制链接]
  • TA的每日心情
    无聊
    昨天 09:21
  • 签到天数: 409 天

    连续签到: 3 天

    [LV.9]测试副司令

    跳转到指定楼层
    1#
    发表于 2023-8-10 13:48:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    对VS Code extension进行单元测试时通常会遇到一个问题,代码中所使用的VS Code编辑器的功能都依赖于vscode库,但是我们在单元测试中并没有添加对vscode库的依赖,所以导致运行单元测试时出错。由于vscode库是作为第三方依赖被引入到我们的VS Code extension中的,所以它并不受我们的控制,最好的办法就是在单元测试中对其中的API进行模拟。本文中我将介绍如何使用Jest来模拟vscode库的API。
      如果你还不太熟悉如何开始创建一个VS Code extension,这里的文档可以教你快速上手。
      创建好VS Code extension项目后,你会发现在根目录下有一个package.json文件,VS Code extension会从中读取配置项来管理UI界面元素,在实际开发中你可能会使用到其中的一些属性。我们可以通过package.json来设置项目所需要的依赖项,这里我们将Jest添加为dev dependency,并添加npm脚本以运行Jest单元测试。
    1. <font color="#000000"><font size="3">npm i -D jest
    2. {
    3.   "scripts": {
    4.     "test": "jest"
    5.   }
    6. }</font></font>
    复制代码
    模拟VS Code node module
      Jest提供了一些mocking的选项,但是因为我们想要模拟整个vscode node module,所以最简单的办法是在与node_modules文件夹相同的位置(通常是项目的根目录)创建一个__mocks__文件夹,并在其中添加一个与要模拟的模块名称相同的文件(vscode.js)。
      你不需要在测试代码中导入该模块,mock会自动加载它。Jest称此为manual mocks。
      这种方法最大的好处是它能将我们的测试代码与所依赖的模块分离,使测试代码看起来更加整洁。这里有一个小问题,新加入的开发者需要知道__mocks__文件夹,否则很难理解单元测试是如何正常工作的,因为单元测试中并没有VS Code模块被模拟的代码。
      以下就是对VS Code模块进行模拟的代码。我们并没有模拟整个API,你可以根据需要进行调整。
    1. <font color="#000000"><font size="3">// vscode.js

    2. const languages = {
    3.   createDiagnosticCollection: jest.fn()
    4. };

    5. const StatusBarAlignment = {};

    6. const window = {
    7.   createStatusBarItem: jest.fn(() => ({
    8.     show: jest.fn()
    9.   })),
    10.   showErrorMessage: jest.fn(),
    11.   showWarningMessage: jest.fn(),
    12.   createTextEditorDecorationType: jest.fn()
    13. };

    14. const workspace = {
    15.   getConfiguration: jest.fn(),
    16.   workspaceFolders: [],
    17.   onDidSaveTextDocument: jest.fn()
    18. };

    19. const OverviewRulerLane = {
    20.   Left: null
    21. };

    22. const Uri = {
    23.   file: f => f,
    24.   parse: jest.fn()
    25. };
    26. const Range = jest.fn();
    27. const Diagnostic = jest.fn();
    28. const DiagnosticSeverity = { Error: 0, Warning: 1, Information: 2, Hint: 3 };

    29. const debug = {
    30.   onDidTerminateDebugSession: jest.fn(),
    31.   startDebugging: jest.fn()
    32. };

    33. const commands = {
    34.   executeCommand: jest.fn()
    35. };

    36. const vscode = {
    37.   languages,
    38.   StatusBarAlignment,
    39.   window,
    40.   workspace,
    41.   OverviewRulerLane,
    42.   Uri,
    43.   Range,
    44.   Diagnostic,
    45.   DiagnosticSeverity,
    46.   debug,
    47.   commands
    48. };

    49. module.exports = vscode;</font></font>
    复制代码
    使用模拟的VS Code模块的示例
      我的开源项目Git Mob for VS code中使用了这种方法,我将用其中的代码来说明如何使用模拟的VS Code模块。
      下面的例子中,VS Code编辑器的状态栏会根据Git钩子prepare-commit-msg是否被调用来做相应的调整,你可以看到这里我并没有将vscode模块导入到我的测试文件中并对其进行模拟。
    1. <font color="#000000"><font size="3">// git-mob-hook-status.spec.js

    2. const { hasPrepareCommitMsgTemplate } = require("../prepare-commit-msg-file");
    3. const { gitMobHookStatus } = require("./git-mob-hook-status");

    4. jest.mock("./../prepare-commit-msg-file");

    5. describe("Hook or template status", function() {
    6.   let mockContext;
    7.   beforeAll(function() {
    8.     mockContext = {
    9.       subscriptions: []
    10.     };
    11.   });

    12.   afterEach(function() {
    13.     hasPrepareCommitMsgTemplate.mockReset();
    14.   });

    15.   it("using git template for co-authors", () => {
    16.     hasPrepareCommitMsgTemplate.mockReturnValue(false);
    17.     const statusBar = gitMobHookStatus({ context: mockContext })();
    18.     expect(statusBar).toEqual(
    19.       expect.objectContaining({
    20.         text: "$(file-code) Git Mob",
    21.         tooltip: "Using .gitmessage template"
    22.       })
    23.     );
    24.   });

    25.   it("using git prepare commit msg for co-authors", () => {
    26.     hasPrepareCommitMsgTemplate.mockReturnValue(true);
    27.     const statusBar = gitMobHookStatus({ context: mockContext })();
    28.     expect(statusBar).toEqual(
    29.       expect.objectContaining({
    30.         text: "$(zap) Git Mob",
    31.         tooltip: "Using prepare-commit-msg hook"
    32.       })
    33.     );
    34.   });
    35. });</font></font>
    复制代码
    你可以在这里查看源代码:
    • git-mob-hook-status.spec.js
    • git-mob-hook-status.js

    我能检查vscode模块中的方法是否被调用了吗?
      你可以导入模拟的vscode模块。下面的代码中,我想要检查当用户修改co-author文件时onDidSaveTextDocument事件是否被订阅了。
    1. <font color="#000000"><font size="3">const vscode = require("../__mocks__/vscode");

    2. // ...
    3. test("Reload co-author list when git-coauthors file saved", () => {
    4.   reloadOnSave(coAuthorProviderStub);
    5.   expect(vscode.workspace.onDidSaveTextDocument).toHaveBeenCalledWith(
    6.     expect.any(Function)
    7.   );
    8.   // ...
    9. });
    10. // ...</font></font>
    复制代码
    可以看到这里都是Jest mock API的标准用法,这意味着我们可以在代码中正常使用vscode模块的方法,而不受manual mock的任何限制。例如,我们还可以使用mockImplementation来修改实现。
      更多示例可以查看这里的源代码:
    • reload-on-save.spec.js

      编写单元测试最大的好处是可以快速得到反馈结果,如果你对TDD(Test-Driven Development,测试驱动开发)情有独钟,那么单元测试将使你对VS Code extension的开发更加信心满满。

    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-5-9 01:42 , Processed in 0.063911 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表