ASP.NET Core SignalR TypeScript 客户端单元测试完全指南:Jest 运行、过滤与调试
【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore
ASP.NET Core SignalR 的 JavaScript/TypeScript 客户端(@microsoft/signalr与@microsoft/signalr-protocol-msgpack)使用 Jest 官方文档,系统讲解如何在clients/ts目录下构建库、运行全部/部分/单个测试,以及在 Visual Studio Code 中调试测试用例。读完本文,你将掌握 SignalR TypeScript 客户端单元测试的完整命令集、Jest 的文件名与-t过滤技巧,以及基于 VS Code 的断点调试工作流。
一、测试框架与前置条件
SignalR 的 TypeScript 客户端单元测试建立在以下技术栈之上:
- Jest:测试运行器与断言框架(当前仓库 package.json 中锁定
jest^29.5.0); - ts-jest:Jest 的 TypeScript 预处理器,自动完成类型检查与转译,省去单独的编译步骤;
- jest-jasmine2:以 Jasmine 2 风格运行测试的 runner(见 jest.config.js 中
testRunner: "jest-jasmine2"),因此测试代码使用describe/it的 Jasmine 风格组织; - @types/jest / @types/node:为测试代码提供类型定义。
在开始之前需要满足两个前置条件:
- 已安装Node.js;
- 自上次
clean之后,至少运行过一次./build.cmd /t:Restore,确保仓库的构建基础设施(包括 npm 依赖还原)就绪。
注意:文档中给出的构建命令
./build.cmd /t:Restore是 Windows 环境写法;Linux/macOS 下对应脚本为仓库根目录的 restore.sh(或./build.sh,视仓库构建脚本而定),请根据实际运行环境选用。
所有命令都必须从clients/ts目录(即 src/SignalR/clients/ts)下执行,因为 npm 脚本与 Jest 配置均以该目录为工作根目录。
测试的组织方式
从仓库源码看,单元测试按包划分为两个测试目录:
- signalr/tests:核心客户端
@microsoft/signalr的测试,覆盖AbortSignal、HttpConnection、HubConnection、HubConnectionBuilder、JsonHubProtocol、LongPollingTransport、WebSocketTransport、ServerSentEventsTransport、TextMessageFormat、UserAgent等主题; - signalr-protocol-msgpack/tests:MessagePack 协议扩展包
@microsoft/signalr-protocol-msgpack的测试,包含BinaryMessageFormatter.test.ts与MessagePackHubProtocol.test.ts。
测试文件统一采用*.test.ts命名,例如 AbortSignal.test.ts、JsonHubProtocol.test.ts。Jest 的匹配规则定义在 jest.config.js 的testRegex:(/__tests__/.*|(\.|/)(test|spec))\.(jsx?|tsx?)$,即命中.test.ts/.spec.ts等模式的文件才会被当作测试执行。
二、运行测试前先构建库
SignalR 的单元测试会直接引用打包产物。在 jest.config.js 中可以看到一个关键映射:
moduleNameMapper: { "^@microsoft/signalr$": "<rootDir>/signalr/dist/cjs/index.js" }也就是说,测试代码中import { ... } from "@microsoft/signalr"实际解析到signalr/dist/cjs/index.js——这是npm run build生成的 CommonJS 打包产物。因此,每次修改库源码后,都必须先重新构建,再运行测试,否则测试运行的仍是旧的构建结果。
在clients/ts目录下执行:
> npm run build该命令会构建@microsoft/signalr与@microsoft/signalr-protocol-msgpack两个库(底层通过 webpack/tsc 完成,相关配置见 webpack.config.base.js 与 tsconfig.base.json)。同时,npm run build也会在signalr/dist/cjs下产出 Jest 所需的 CommonJS 入口。
三、运行全部测试
在clients/ts目录下执行:
> npm test该命令实际调用的是jest --config ./jest.config.js(见 package.json 中的test脚本)。在进入 Jest 之前,pretest钩子还会先运行 ESLint 对两个测试目录做静态检查:
"pretest": "npm run lint-signalr & npm run lint-signalr-msgpack"npm test会运行两个包的全部*.test.ts文件,并在终端输出每个套件/用例的通过情况。此外 package.json 还提供了覆盖率脚本npm run coverage(等价于jest --config ./jest.config.js --coverage),需要度量代码覆盖率时可使用它。
测试结果默认输出到终端;同时 jest.config.js 配置了jest-junitreporter,会把 JUnit 格式的结果写入../../../../artifacts/log/<platform>.signalr.junit.xml(即仓库根目录的 artifacts/log 下),便于 CI 集成。
四、运行特定文件中的全部测试
npm test接受附加参数并透传给 Jest:
> npm test -- FileName其中FileName可以是路径的一个子串,Jest 会运行路径中包含该子串的所有测试文件。文档强调:即使在 Windows 上,路径分隔符也请使用/,因为参数最终由 Node 解析。
官方文档给出的示例(均基于clients/ts目录):
| 命令 | 运行范围 |
|---|---|
npm test -- signalr/tests | clients\ts\signalr\tests下的全部测试 |
npm test -- signalr-protocol-msgpack/tests | clients\ts\signalr-protocol-msgpack\tests下的全部测试 |
npm test -- signalr/tests/ | clients\ts\signalr\tests下的全部测试(尾部斜杠写法同样有效) |
npm test -- signalr/tests/JsonHubProtocol | signalr/tests/JsonHubProtocol.test.ts |
npm test -- JsonHubProtocol | 同样运行signalr/tests/JsonHubProtocol.test.ts(因为它是唯一匹配该子串的测试文件) |
由此可见,文件过滤是“子串包含”匹配而非“前缀/后缀”匹配,JsonHubProtocol与signalr/tests/JsonHubProtocol都能命中同一文件。实际仓库中该文件为 JsonHubProtocol.test.ts,其中包含对 Invocation 消息读写、Date 参数序列化、headers 传递、消息轮询等场景的断言。
五、运行单个测试
运行单个测试有两种方式,各有适用场景。
方式一:.only临时标记(最简单)
Jest 支持在it上追加.only,被标记的用例会成为该文件中唯一运行的测试。官方文档的示例:
describe("A suite of tests", () => { describe("A sub-suite of tests", () => { it.only("will run", () => { }); it("will not run", () => { }); }); describe("Another sub-suite of tests", () => { it("will not run either", () => { }); }); });注意两点:
- 若同时运行多个文件(例如不带参数直接
npm test),其他文件中的测试仍然会照常运行,.only只对所在文件生效; - 调试完务必移除
.only,避免后续提交时误伤其他用例。
方式二:-t参数按名称过滤(无需改代码)
Jest 的-t参数接收一个子串模式,用于匹配测试的完整名称(由describe名称 +it名称拼接而成)。为了加快执行速度,官方建议把-t与文件路径过滤参数配合使用。
以官方文档中的示例代码(该示例与仓库真实文件 AbortSignal.test.ts 结构一致)为例:
describe("AbortSignal", () => { describe("aborted", () => { it("is false on initialization", () => { // ... }); it("is true when aborted", () => { // ... }); }); describe("onabort", () => { it("is called when abort is called", () => { // ... }); }); });对应命令与运行结果:
| 命令 | 运行的测试 |
|---|---|
npm test -- AbortSignal -t "AbortSignal aborted" | AbortSignal aborted is false on initialization和AbortSignal aborted is true when aborted |
npm test -- AbortSignal -t "is called when abort is called" | AbortSignal onabort is called when abort is called |
第一条命令中,AbortSignal把文件过滤到 AbortSignal.test.ts,-t "AbortSignal aborted"匹配名称中同时包含这两个词的用例(外层describe("AbortSignal")+ 内层describe("aborted")组合成前缀AbortSignal aborted)。第二条命令的-t子串只命中onabort子套件中的it("is called when abort is called"),因为其完整名称为AbortSignal onabort is called when abort is called。
对比两种方式:.only需要修改测试源码、适合快速聚焦单个用例;-t不动源码、适合按名称模式批量筛选,二者可以组合使用(例如在文件中标记.only,再用 VS Code 的“Jest - Current File”调试)。
六、在 Visual Studio Code 中调试测试
仓库文档提供了两种开箱即用的 VS Code 调试配置,无需手动编写launch.json。
调试全部测试
- 打开 VS Code 左侧的Run and Debug(调试)面板;
- 在顶部的配置下拉框中选择"Jest - All";
- 点击播放按钮,或直接按F5。
该配置会在调试器下运行全部单元测试,适合全局回归排查。
调试当前文件中的全部测试
- 打开 VS Code 左侧的Run and Debug(调试)面板;
- 在顶部的配置下拉框中选择"Jest - Current File";
- 点击播放按钮,或直接按F5。
该配置只运行当前打开的编辑器文件中的测试,配合.only即可精确调试单个用例。官方文档特别提醒:将 "Jest - Current File" 与.only搭配使用,是调试单个测试的最便捷方式。
提示:仓库内未在
clients/ts下发现.vscode/launch.json,上述两个配置由仓库的 VS Code 任务/调试基础设施提供(该文档即为其权威说明)。若你的环境中未出现这两个配置项,可确认已通过仓库构建脚本完成 VS Code 工作区设置,或参照 Jest 官方文档配置等价调试参数。
七、调试定位的源码参考
当某个测试失败时,可以借助以下仓库路径快速定位被测实现与相关测试,形成“源码—测试”对照:
- 核心客户端源码目录:src/SignalR/clients/ts/signalr/src(包含
HubConnection、HttpConnection、JsonHubProtocol、各传输实现等); - 核心客户端测试目录:src/SignalR/clients/ts/signalr/tests;
- MessagePack 协议包源码:src/SignalR/clients/ts/signalr-protocol-msgpack/src,对应测试在 src/SignalR/clients/ts/signalr-protocol-msgpack/tests;
- 与单元测试配套的还有浏览器端功能测试文档 JSFunctionalTests.md,用于端到端验证传输与协议在真实浏览器中的行为。
八、常见问题与最佳实践
- 改了源码但测试结果没变:多半是忘记先执行
npm run build。由于moduleNameMapper指向signalr/dist/cjs/index.js,不重新构建就无法验证最新代码。 - 过滤条件不生效:确认
FileName是路径子串且使用/分隔符;-t的子串需与describe+it拼接后的完整名称匹配。 - 提交前清理
.only:.only是临时调试标记,遗留到 CI 会导致大量用例被跳过。 - 充分利用类型检查:tsconfig.jest.json 继承 tsconfig.base.json,开启
strict与noImplicitAny等严格选项,测试代码同样享受完整类型检查,遇到编译错误时先修类型再跑测试。
九、命令速查表
| 目的 | 命令(在clients/ts目录下) |
|---|---|
| 构建库(改源码后必跑) | npm run build |
| 运行全部测试 | npm test |
| 运行某路径下的全部测试 | npm test -- signalr/tests |
| 运行单个测试文件 | npm test -- JsonHubProtocol |
| 按名称子串运行指定文件内的用例 | npm test -- AbortSignal -t "AbortSignal aborted" |
| 生成覆盖率报告 | npm run coverage |
| 调试全部测试(VS Code) | 选择 "Jest - All" 后按 F5 |
| 调试当前文件测试(VS Code) | 选择 "Jest - Current File" 后按 F5,建议配合.only |
按照上述流程,你可以从“改代码 →npm run build→npm test -- <过滤>→ 断点调试”的完整闭环中高效迭代 SignalR TypeScript 客户端的开发与验证工作。
【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考