TypeScript项目中使用Sinon Mock导入对象及未导出函数的方法咨询
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
aorb, you can stub those properties right after importingexportedFullName: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
exportedFullNamevariable itself is read-only, the object it points to is mutable.Replace the entire module export: If you need to swap out the whole
exportedFullNameobject, use a tool likeproxyquire(for CommonJS) oresmock(for ES modules) to replace thefullName.tsmodule 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,
esmockis 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

