You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript项目中使用Sinon Mock导入对象及未导出函数的方法咨询

Mocking exportedFullName in Your TypeScript Project (Sinon + Jest Options)

Let's break down your questions one by one, prioritizing Sinon-based solutions as you requested:

1. Can I directly mock/stub the imported exportedFullName with Sinon?

You can't do this with Sinon alone, but combining it with a module-mocking tool makes it possible. Here's how:

ES module exports are static and read-only at the top level—you can't reassign the entire exportedFullName object directly using Sinon. However, since exportedFullName is an object with mutable properties, you have two solid approaches:

  • Stub individual properties: If you just need to override the values of a or b, you can stub those properties right after importing exportedFullName:

    import { exportedFullName } from '../../fullName';
    import sinon from 'sinon';
    
    describe('Your test suite', () => {
      it('uses mocked exportedFullName properties', () => {
        // Override the properties with your mock values
        sinon.stub(exportedFullName, 'a').value('my-mocked-fullname-a');
        sinon.stub(exportedFullName, 'b').value('my-mocked-fullname-b');
    
        // Run your main function tests here—your helper code will pick up the mocked values
      });
    });
    

    Note: This works because while the exportedFullName variable itself is read-only, the object it points to is mutable.

  • Replace the entire module export: If you need to swap out the whole exportedFullName object, use a tool like proxyquire (for CommonJS) or esmock (for ES modules) to replace the fullName.ts module before importing your helper/main code. Example with proxyquire:

    import proxyquire from 'proxyquire';
    import sinon from 'sinon';
    
    describe('Your test suite', () => {
      it('mocks the entire exportedFullName object', () => {
        const mockedFullNameModule = {
          exportedFullName: { a: 'mock-a', b: 'mock-b' }
        };
    
        // Import helper.ts, but replace its dependency on fullName.ts with our mock
        const helper = proxyquire('../../helper', {
          '../../fullName': mockedFullNameModule
        });
    
        // Now any code in helper.ts that uses exportedFullName will use your mock
      });
    });
    

    For ES modules, esmock is the way to go—it supports ES module syntax natively and works similarly to proxyquire.

2. Can I mock the unexported getFullName function to control exportedFullName?

Sinon can't do this out of the box, since getFullName is a private, unexported function that's not attached to any accessible object. Sinon only works with functions that are either exported or part of an object/instance you can access in your tests.

Here are your options to handle this:

Option 1: Switch to Jest (simpler for private function/mock scenarios)

Jest makes this straightforward by letting you mock entire modules, even overriding the behavior of unexported functions indirectly. You can either mock the exportedFullName directly, or mock process.env to control what getFullName returns:

Mock exportedFullName directly:

// main.test.ts
jest.mock('../../fullName', () => ({
  exportedFullName: {
    a: 'jest-mocked-a',
    b: 'jest-mocked-b'
  }
}));

import { main } from './main';

test('main function uses mocked exportedFullName', () => {
  main();
  // Add your assertions here—they'll use the mocked values
});

Mock process.env to control getFullName:

Since getFullName reads from process.env, you can just mock the environment variables directly:

beforeEach(() => {
  // Set mock env vars before each test
  process.env['string-a'] = 'env-mock-a';
  process.env['string-b'] = 'env-mock-b';
});

afterEach(() => {
  // Clean up after tests
  delete process.env['string-a'];
  delete process.env['string-b'];
});

import { main } from './main';

test('main function uses mocked env values', () => {
  main();
  // Assertions will use the env values you set
});

This approach avoids mocking the function entirely and works with your existing code.

Option 2: Adjust production code to use Sinon

If you want to stick with Sinon, you'll need to make getFullName accessible. The simplest way is to export it directly:

// fullName.ts
export function getFullName(name: string): string { 
  const fullName = process.env[name]; 
  return fullName; 
}

export const exportedFullName: CustomObj = { 
  a: getFullName('string-a'), 
  b: getFullName('string-b') 
};

Now you can stub getFullName using Sinon combined with a module-mocking tool like proxyquire:

import proxyquire from 'proxyquire';
import sinon from 'sinon';

describe('Test with stubbed getFullName', () => {
  it('controls exportedFullName via stubbed getFullName', () => {
    // Create a stub for getFullName that returns custom values
    const getFullNameStub = sinon.stub()
      .withArgs('string-a').returns('sinon-mock-a')
      .withArgs('string-b').returns('sinon-mock-b');

    // Mock the fullName module with our stubbed function
    const mockedFullNameModule = {
      getFullName: getFullNameStub,
      exportedFullName: {
        a: getFullNameStub('string-a'),
        b: getFullNameStub('string-b')
      }
    };

    // Import helper.ts with the mocked module
    const helper = proxyquire('../../helper', {
      '../../fullName': mockedFullNameModule
    });

    // Run your tests here—exportedFullName will use the stubbed values
  });
});

Alternatively, you could refactor exportedFullName to be a function that calls getFullName when invoked, which makes dependency injection and stubbing even easier.


内容的提问来源于stack exchange,提问作者Sabo Boz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:32:29