测试扩展
Visual Studio Code 支持运行和调试您的扩展的测试。这些测试将在名为 扩展开发主机 的特殊 VS Code 实例中运行,并具有对 VS Code API 的完全访问权限。我们将这些测试称为集成测试,因为它们超越了可以在没有 VS Code 实例的情况下运行的单元测试。本文档重点介绍 VS Code 集成测试。
概述
如果您正在使用Yeoman Generator来搭建扩展,那么集成测试已经为您创建好了。
在生成的扩展中,你可以使用 npm run test
或 yarn test
来运行集成测试,这些测试:
- 下载并解压最新版本的VS Code。
- 运行由扩展测试运行脚本指定的Mocha测试。
快速设置:测试CLI
VS Code 团队发布了一个命令行工具来运行扩展测试。你可以在扩展示例仓库中找到一个示例。
测试CLI提供了快速设置,并且还允许您使用Extension Test Runner轻松运行和调试VS Code UI的测试。CLI在底层专门使用Mocha。
要开始使用,您首先需要安装@vscode/test-cli
模块,以及@vscode/test-electron
模块,该模块允许在VS Code桌面版中运行测试:
npm install --save-dev @vscode/test-cli @vscode/test-electron
安装模块后,您将拥有vscode-test
命令行,您可以将其添加到package.json
中的scripts
部分:
{
"name": "my-cool-extension",
"scripts": {
+ "test": "vscode-test"
vscode-test
会在当前工作目录下寻找一个 .vscode-test.js/mjs/cjs
文件。该文件提供了测试运行器的配置,你可以在这里找到完整的定义 here。
常见选项包括:
- (必填)
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', () => {
suiteTeardown(() => {
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));
});
});
你可以使用npm test
命令运行此测试,或者在安装Extension Test Runner后,在VS Code中使用Test: Run All Tests命令。你也可以使用Test: Debug All Tests命令调试测试。
高级设置:您自己的运行器
您可以在helloworld-test-sample中找到本指南的配置。本文档的其余部分将在示例的上下文中解释这些文件:
- 测试脚本 (
src/test/runTest.ts
) - 测试运行脚本 (
src/test/suite/index.ts
)
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-electron
API 来简化下载、解压和启动带有扩展测试参数的 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-electron
API 还允许:
- 使用特定工作区启动VS Code。
- 下载不同版本的VS Code,而不是最新的稳定版本。
- 使用额外的CLI参数启动VS Code。
你可以在microsoft/vscode-test找到更多API使用示例。
测试运行脚本
在运行扩展集成测试时,--extensionTestsPath
指向 测试运行脚本 (src/test/suite/index.ts
),该脚本以编程方式运行测试套件。以下是 helloworld-test-sample
的 测试运行脚本,它使用 Mocha 来运行测试套件。你可以以此为起点,并使用 Mocha 的 API 自定义你的设置。你也可以用任何其他可以以编程方式运行的测试框架替换 Mocha。
import * as path from 'path';
import * as Mocha from 'mocha';
import { 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 })
.then(files => {
// 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);
}
})
.catch(err => {
return 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.
一般来说,如果你从命令行界面运行扩展测试,测试运行的版本不能已经在运行。作为一种解决方法,你可以在VS Code稳定版中运行测试,并使用VS Code Insiders进行开发。只要你不是在VS Code Insiders中从命令行界面运行测试,而是在VS Code稳定版中运行,这种设置就能正常工作。
另一种方法是从VS Code内部的调试启动配置中运行扩展测试。这还有一个额外的优势,即你甚至可以调试测试。
调试时禁用其他扩展
当你在VS Code中调试扩展测试时,VS Code会使用全局安装的VS Code实例,并加载所有已安装的扩展。你可以将--disable-extensions
配置添加到launch.json
或@vscode/test-electron
的runTests
API的launchArgs
选项中。
{
"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的持续集成服务中运行您的扩展测试。