Mocha中sinon.spy始终显示函数调用次数为0的问题求助
Hey there! Let's troubleshoot why your Sinon spies aren't picking up calls to callchildfunc and childfunc2 when you run parent(). This is a super common gotcha for folks new to testing with spies, so let's break down the most likely issues and fix them step by step.
1. Make sure you're spying on the exact function reference that parent() calls
This is the #1 reason spies show 0 calls. If your parent() function is using a local copy of the child functions, or referencing them from a different module/scope than the one you're spying on, the spy won't track the calls.
Let's use a concrete example. Suppose your code looks like this:
// childFuncs.js export function callchildfunc() { /* ... */ } export function childfunc2() { /* ... */ } // parent.js import { callchildfunc, childfunc2 } from './childFuncs'; export function parent() { callchildfunc(); childfunc2(); }
In your test, you need to spy on the exported functions from childFuncs.js—not some redefined version in your test file. Here's how to do it correctly:
import { expect } from 'chai'; import sinon from 'sinon'; import * as childFuncs from './childFuncs'; import { parent } from './parent'; describe('parent() function', () => { it('should call callchildfunc and childfunc2', () => { // Create spies on the actual functions parent() uses const callChildSpy = sinon.spy(childFuncs, 'callchildfunc'); const childFunc2Spy = sinon.spy(childFuncs, 'childfunc2'); // Trigger the parent function (don't forget this step!) parent(); // Assert the spies were called expect(callChildSpy.calledOnce).to.be.true; expect(childFunc2Spy.calledOnce).to.be.true; // Clean up: restore the original functions to avoid breaking other tests callChildSpy.restore(); childFunc2Spy.restore(); }); });
2. Watch out for local function references
If your parent() function defines the child functions internally, or uses a local copy instead of an exported/imported one, your spy won't work. For example:
// ❌ Bad: parent uses a local function, not the exported one function callchildfunc() { /* ... */ } export function parent() { callchildfunc(); // This calls the local version, not the one you spied on }
To fix this, refactor your code so parent() depends on external child functions (like the module export example above) that you can spy on.
3. Handle async functions if needed
If parent() or your child functions are asynchronous, you need to wait for the async operations to finish before asserting. Use async/await in your test:
it('should call async child functions', async () => { const asyncSpy = sinon.spy(childFuncs, 'asyncChildFunc'); // Wait for parent() to complete its async work await parent(); expect(asyncSpy.calledOnce).to.be.true; asyncSpy.restore(); });
4. Double-check you're actually calling parent()
It sounds silly, but it's easy to forget! If you create the spies but never run parent() in your test, the call count will always be 0. Don't skip that step.
Quick recap
The core fix is ensuring your spy is attached to the exact function reference that parent() invokes. Spies work by wrapping the function they're attached to—if parent() is using a different copy, the spy can't track the calls.
内容的提问来源于stack exchange,提问作者Henry

