测试扩展

Visual Studio Code 支持运行和调试扩展测试。这些测试将在名为Extension Development Host的 VS Code 特殊实例内运行,并具有对 VS Code API 的完全访问权限。我们将这些测试称为集成测试,因为它们超越了无需 VS Code 实例即可运行的单元测试。本文档重点介绍 VS Code 集成测试。

概述

如果您使用Yeoman Generator来构建扩展,那么已经为您创建了集成测试。

在生成的扩展中,您可以使用npm run testyarn test运行集成测试:

  • 下载并解压最新版本的 VS Code。
  • 运行扩展测试运行程序脚本指定的Mocha测试。

快速设置:测试 CLI

VS Code 团队发布了一个命令行工具来运行扩展测试。您可以在扩展示例存储库中找到示例。

测试 CLI 提供快速设置,还允许您使用Extension Test Runner轻松运行和调试 VS Code UI 测试。CLI在底层专门使用Mocha 。

首先,您需要首先安装该@vscode/test-cli模块以及@vscode/test-electron允许在 VS Code Desktop 中运行测试的模块:

npm install --save-dev @vscode/test-cli @vscode/test-electron

安装模块后,您将获得vscode-test命令行,您可以将其添加到以下scripts部分package.json

{
  "name": "my-cool-extension",
  "scripts": {
+   "test": "vscode-test"

vscode-test查找.vscode-test.js/mjs/cjs相对于当前工作目录的文件。该文件提供测试运行器的配置,您可以在此处找到完整的定义。

常见选项包括:

  • (必需) files - 包含要运行的测试的模式、模式列表或绝对路径。
  • version- 用于运行测试的 VS Code 版本(默认为stable)。
  • workspaceFolder- 测试期间打开的工作空间的路径。
  • extensionDevelopmentPath- 扩展文件夹的路径(默认为配置文件的目录)。
  • mocha- 包含传递给 Mocha 的附加选项的对象。

配置可能很简单:

// .vscode-test.js
const { defineConfig } = require('@vscode/test-cli');

module.exports = defineConfig({ files: 'out/test/**/*.test.js' });

...或更高级:

// .vscode-test.js
const { defineConfig } = require('@vscode/test-cli');

module.exports = defineConfig([
  {
    label: 'unitTests',
    files: 'out/test/**/*.test.js',
    version: 'insiders',
    workspaceFolder: './sampleWorkspace',
    mocha: {
      ui: 'tdd',
      timeout: 20000
    }
  }
  // you can specify additional test configurations, too
]);

如果您通过传递数组来定义多个配置,则它们将在您运行时按顺序运行vscode-test。您可以按 进行过滤label并使用标志单独运行它们--label,例如vscode-test --label unitTests。运行vscode-test --help以获得完整的命令行选项集。

测试脚本

CLI 设置完毕后,您就可以编写并运行测试。测试脚本可以访问 VS Code API,并在 Mocha 下运行。这是一个示例(src/test/suite/extension.test.ts):

import * as assert from 'assert';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../extension';

suite('Extension Test Suite', () => {
  after(() => {
    vscode.window.showInformationMessage('All tests done!');
  });

  test('Sample test', () => {
    assert.strictEqual(-1, [1, 2, 3].indexOf(5));
    assert.strictEqual(-1, [1, 2, 3].indexOf(0));
  });
});

您可以使用以下命令运行此测试,或者在安装Extension Test Runnernpm test后在 VS Code 中使用“测试:运行所有测试”命令来运行此测试。您还可以使用“测试:调试所有测试”命令来调试测试。

高级设置:您自己的跑步者

您可以在helloworld-test-sample中找到本指南的配置。本文档的其余部分在示例上下文中解释了这些文件:

VS Code 提供了两个用于运行扩展测试的 CLI 参数,--extensionDevelopmentPath以及--extensionTestsPath.

例如:

# - Launches VS Code Extension Host
# - Loads the extension at <EXTENSION-ROOT-PATH>
# - Executes the test runner script at <TEST-RUNNER-SCRIPT-PATH>
code \
--extensionDevelopmentPath=<EXTENSION-ROOT-PATH> \
--extensionTestsPath=<TEST-RUNNER-SCRIPT-PATH>

测试脚本( src/test/runTest.ts) 使用@vscode/test-electronAPI 来简化下载、解压和启动带有扩展测试参数的 VS Code 的过程:

import * as path from 'path';

import { runTests } from '@vscode/test-electron';

async function main() {
  try {
    // The folder containing the Extension Manifest package.json
    // Passed to `--extensionDevelopmentPath`
    const extensionDevelopmentPath = path.resolve(__dirname, '../../');

    // The path to the extension test runner script
    // Passed to --extensionTestsPath
    const extensionTestsPath = path.resolve(__dirname, './suite/index');

    // Download VS Code, unzip it and run the integration test
    await runTests({ extensionDevelopmentPath, extensionTestsPath });
  } catch (err) {
    console.error(err);
    console.error('Failed to run tests');
    process.exit(1);
  }
}

main();

@vscode/test-electronAPI 还允许:

  • 使用特定工作区启动 VS Code。
  • 下载不同版本的 VS Code,而不是最新的稳定版本。
  • 使用附加 CLI 参数启动 VS Code。

您可以在microsoft/vscode-test找到更多 API 使用示例。

测试运行脚本

运行扩展集成测试时,--extensionTestsPath指向以编程方式运行测试套件的测试运行器脚本( )。src/test/suite/index.ts下面是使用 Mocha 运行测试套件的测试运行器脚本。helloworld-test-sample您可以以此为起点,并使用Mocha 的 API自定义您的设置。您还可以将 Mocha 替换为任何其他可以以编程方式运行的测试框架。

import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';

export function run(): Promise<void> {
  // Create the mocha test
  const mocha = new Mocha({
    ui: 'tdd',
    color: true
  });

  const testsRoot = path.resolve(__dirname, '..');

  return new Promise((c, e) => {
    glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
      if (err) {
        return e(err);
      }

      // Add files to the test suite
      files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));

      try {
        // Run the mocha test
        mocha.run(failures => {
          if (failures > 0) {
            e(new Error(`${failures} tests failed.`));
          } else {
            c();
          }
        });
      } catch (err) {
        e(err);
      }
    });
  });
}

测试运行器脚本和*.test.js文件都可以访问 VS Code API。

这是一个示例测试(src/test/suite/extension.test.ts):

import * as assert from 'assert';
import { after } from 'mocha';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../extension';

suite('Extension Test Suite', () => {
  after(() => {
    vscode.window.showInformationMessage('All tests done!');
  });

  test('Sample test', () => {
    assert.strictEqual(-1, [1, 2, 3].indexOf(5));
    assert.strictEqual(-1, [1, 2, 3].indexOf(0));
  });
});

调试测试

调试测试与调试扩展类似。

以下是launch.json调试器配置示例:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Extension Tests",
      "type": "extensionHost",
      "request": "launch",
      "runtimeExecutable": "${execPath}",
      "args": [
        "--extensionDevelopmentPath=${workspaceFolder}",
        "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
      ],
      "outFiles": ["${workspaceFolder}/out/test/**/*.js"]
    }
  ]
}

尖端

使用 Insiders 版本进行扩展开发

由于 VS Code 的限制,如果您使用 VS Code 稳定版本并尝试在 CLI 上运行集成测试,则会抛出错误:

Running extension tests from the command line is currently only supported if no other instance of Code is running.

一般来说,如果您从 CLI 运行扩展测试,则运行测试所使用的版本不能已经运行。作为解决方法,您可以在 VS Code Stable 中运行测试并使用VS Code Insiders进行开发。只要您不是在 VS Code Insiders 中而是在 VS Code Stable 中从 CLI 运行测试,此设置就可以正常工作。

另一种方法是从 VS Code 本身的调试启动配置运行扩展测试。这还有一个额外的优点,您甚至可以调试测试。

调试时禁用其他扩展

当您在 VS Code 中调试扩展测试时,VS Code 使用全局安装的 VS Code 实例,并将加载所有已安装的扩展。您可以在API 的或选项--disable-extensions中添加配置。launch.jsonlaunchArgs@vscode/test-electronrunTests

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Extension Tests",
      "type": "extensionHost",
      "request": "launch",
      "runtimeExecutable": "${execPath}",
      "args": [
        "--disable-extensions",
        "--extensionDevelopmentPath=${workspaceFolder}",
        "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
      ],
      "outFiles": ["${workspaceFolder}/out/test/**/*.js"]
    }
  ]
}
await runTests({
  extensionDevelopmentPath,
  extensionTestsPath,
  /**
   * A list of launch arguments passed to VS Code executable, in addition to `--extensionDevelopmentPath`
   * and `--extensionTestsPath` which are provided by `extensionDevelopmentPath` and `extensionTestsPath`
   * options.
   *
   * If the first argument is a path to a file/folder/workspace, the launched VS Code instance
   * will open it.
   *
   * See `code --help` for possible arguments.
   */
  launchArgs: ['--disable-extensions']
});

自定义设置@vscode/test-electron

有时您可能想要运行自定义设置,例如code --install-extension在开始测试之前运行以安装另一个扩展。@vscode/test-electron有一个更细粒度的 API 来适应这种情况:

import * as cp from 'child_process';
import * as path from 'path';
import {
  downloadAndUnzipVSCode,
  resolveCliArgsFromVSCodeExecutablePath,
  runTests
} from '@vscode/test-electron';

async function main() {
  try {
    const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
    const extensionTestsPath = path.resolve(__dirname, './suite/index');
    const vscodeExecutablePath = await downloadAndUnzipVSCode('1.40.1');
    const [cliPath, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath);

    // Use cp.spawn / cp.exec for custom setup
    cp.spawnSync(
      cliPath,
      [...args, '--install-extension', '<EXTENSION-ID-OR-PATH-TO-VSIX>'],
      {
        encoding: 'utf-8',
        stdio: 'inherit'
      }
    );

    // Run the extension test
    await runTests({
      // Use the specified `code` executable
      vscodeExecutablePath,
      extensionDevelopmentPath,
      extensionTestsPath
    });
  } catch (err) {
    console.error('Failed to run tests');
    process.exit(1);
  }
}

main();

下一步

  • 持续集成- 在持续集成服务(例如 Azure DevOps)中运行扩展测试。