如何用Sinon测试TS类实例化参数?解决TS2345类型错误
问题:TypeScript中用Sinon Stub Auth0构造器时出现类型错误
我在Node.js的TypeScript环境中使用Auth0,现有待测试类ClassToTest,其静态方法getClient会基于全局配置创建AuthenticationClient实例并返回。我希望编写单元测试验证传入AuthenticationClient的options参数值是否正确,尝试用Sinon stub构造器时出现TypeScript错误:
error TS2345: Argument of type 'constructor' is not assignable to parameter of type 'keyof AuthenticationClient'
相关代码
ClassToTest.ts
import { AuthenticationClient, AuthenticationClientOptions } from 'auth0'; export class ClassToTest { public static getClient(): AuthenticationClient { let options = { domain: global.myConfig.DOMAIN, clientId: global.myConfig.CLIENT, clientSecret: global.myConfig.SECRET } as AuthenticationClientOptions; let auth0 = new AuthenticationClient(options); return auth0; } } export default ClassToTest;
测试代码(原错误版本)
import { expect } from "chai"; import * as sinon from 'sinon'; import ClassToTest from "./ClassToTest"; import { AuthenticationClient, AuthenticationClientOptions } from "auth0"; describe("ClassToTest", () => { beforeEach(() => { global.myConfig.DOMAIN = 'someValue'; }); afterEach(() => { sinon.restore(); }); it("uses right options", async function () { let usedOptions: AuthenticationClientOptions; sinon.stub(AuthenticationClient.prototype, 'constructor') .callsFake((opts: AuthenticationClientOptions) => { usedOptions = opts; }); expect(usedOptions.domain).to.equal('someValue'); }); });
解决方法
Sinon无法直接stub类原型上的constructor属性(TypeScript类型定义中constructor不属于AuthenticationClient的实例键集合),正确做法是直接stub整个AuthenticationClient类的构造函数:
修改后的测试代码
import { expect } from "chai"; import * as sinon from 'sinon'; import ClassToTest from "./ClassToTest"; import { AuthenticationClient, AuthenticationClientOptions } from "auth0"; describe("ClassToTest", () => { beforeEach(() => { global.myConfig = { DOMAIN: 'someValue', CLIENT: 'test-client-id', SECRET: 'test-secret' }; }); afterEach(() => { sinon.restore(); }); it("uses right options", function () { let usedOptions: AuthenticationClientOptions; // 直接 stub 整个 AuthenticationClient 类的构造函数 const authStub = sinon.stub(AuthenticationClient, 'constructor') .callsFake((opts: AuthenticationClientOptions) => { usedOptions = opts; // 返回一个空对象模拟实例,避免后续代码报错 return {} as AuthenticationClient; }); // 触发构造函数调用 ClassToTest.getClient(); // 断言参数是否正确 expect(usedOptions?.domain).to.equal('someValue'); expect(usedOptions?.clientId).to.equal('test-client-id'); expect(usedOptions?.clientSecret).to.equal('test-secret'); // 验证构造函数被调用一次 expect(authStub.calledOnce).to.be.true; }); });
关键说明
- 直接Stub类本身:通过
sinon.stub(AuthenticationClient, 'constructor')替换类的构造函数,而非原型上的constructor,这样能避开TypeScript的类型检查问题。 - 触发构造调用:必须调用
ClassToTest.getClient(),否则构造函数不会执行,usedOptions会是undefined。 - 返回模拟实例:在fake函数中返回一个符合
AuthenticationClient类型的空对象,避免原代码中返回实例时出现类型错误。
内容的提问来源于stack exchange,提问作者zaitsman
相关产品推荐
相关产品推荐

