如何使用Sinon为TypeScript导出类型创建Stub实例?
解决TypeScript中无法为类型创建Sinon Stub的问题
刚从C#转TypeScript确实会遇到这类概念差异的问题,我来帮你理清楚原因和解决方案:
问题根源:TypeScript类型 vs 值的区别
你遇到的报错'LoaderTranslation' only refers to a type, but being used as a value here,核心原因是TypeScript的type只是编译时的类型注解,编译后会被完全擦除,在运行时根本不存在这个"值"。
而Sinon的createStubInstance需要传入的是一个可实例化的构造函数/类(也就是运行时存在的值)——这和C#里类既是类型又是可实例化实体的逻辑不一样,C#里你可以直接对类创建mock,但TS的类型别名只是给结构做了个"标签",没有对应的运行时对象。
具体解决方案
根据你的测试场景,有两种简单可行的方式:
方案1:直接创建符合类型的模拟对象(最常用)
既然LoaderTranslations是一个嵌套的对象类型,你完全可以手动创建一个符合结构的普通对象,不需要用createStubInstance。如果需要验证行为,再用Sinon的spy/fake包装:
import { BaseLoader } from './interface/base-loader'; import { LoaderTranslations } from './interface/dictionary'; // 注意你之前的导入写错了,是LoaderTranslations不是LoadedTranslations describe(`test`, () => { let loaderMock: sinon.SinonStubInstance<BaseLoader>; let mockTranslations: LoaderTranslations; beforeEach(() => { loaderMock = sinon.createStubInstance(BaseLoader); // 创建符合LoaderTranslations类型的模拟数据 mockTranslations = { 'en-US': { 'welcome': 'Hello!', 'logout': 'Sign out' }, 'zh-CN': { 'welcome': '你好!', 'logout': '退出登录' } }; // 让BaseLoader的stub方法返回这个模拟数据的Promise loaderMock.loadTranslations.resolves(mockTranslations); }); // 测试用例示例 it('should load translations correctly', async () => { const result = await loaderMock.loadTranslations(['en-US', 'zh-CN']); expect(result['en-US'].welcome).toBe('Hello!'); // 验证loadTranslations方法被正确调用 expect(loaderMock.loadTranslations.calledWith(['en-US', 'zh-CN'])).toBe(true); }); });
方案2:如果需要对对象属性做行为验证
如果你的测试需要验证某个翻译键是否被访问,可以用Sinon的fake来包装对象属性:
const mockEnTranslations = { 'welcome': sinon.fake.returns('Hello!') }; const mockTranslations: LoaderTranslations = { 'en-US': mockEnTranslations }; // 在测试中调用后,验证fake是否被触发 expect(mockEnTranslations.welcome.called).toBe(true);
总结
不用纠结于给TypeScript类型创建stub——因为它本来就不是运行时存在的东西。你只需要创建符合类型结构的模拟数据,然后通过stub BaseLoader的方法返回它,就能满足绝大多数测试场景了。
内容的提问来源于stack exchange,提问作者Joseph Katzman
相关产品推荐
相关产品推荐

