| name | azure-functions-test-mocking |
| description | Patterns for unit testing Azure Functions with Jest, including module isolation for side-effect-heavy handlers |
| domain | testing |
| confidence | high |
| source | earned |
Context
Azure Functions handlers often have module-scope side effects (App Insights setup, database client init). Standard jest.mock() doesn't reset between tests, causing cross-test pollution. This skill covers the isolation pattern.
Patterns
1. Module isolation via jest.resetModules() + jest.isolateModules()
function loadHandler(mockOverrides) {
jest.resetModules();
let handler;
jest.isolateModules(() => {
jest.doMock('applicationinsights', () => ({ }));
jest.doMock('@azure/cosmos', () => ({ }), { virtual: true });
handler = require('./index');
});
return handler;
}
function loadHandlerWithSetupCrash() {
jest.resetModules();
let handler;
jest.isolateModules(() => {
jest.doMock('applicationinsights', () => ({
setup: jest.fn(() => { throw new Error('Init failed'); }),
defaultClient: null,
}));
jest.doMock('@azure/cosmos', () => ({ }), { virtual: true });
handler = require('./index');
});
return handler;
}
- Call
loadHandler() in each test for fresh module scope
- Use
jest.doMock() (not jest.mock()) inside isolateModules
- Add
{ virtual: true } for packages not yet installed
jest.resetModules() before isolateModules is defensive best practice
2. Mock Azure Functions context
function createMockContext(overrides = {}) {
const log = jest.fn();
log.error = jest.fn();
log.warn = jest.fn();
log.info = jest.fn();
return {
log, res: null, bindings: {},
traceContext: { traceparent: 'test-trace-id' },
done: jest.fn(),
...overrides,
};
}
3. Falsy-valid edge cases
Always test { bpm: 0, isCorrect: false } to catch truthy-based validation bugs.
4. Client principal header testing
function base64Encode(obj) {
return Buffer.from(JSON.stringify(obj)).toString('base64');
}
5. Comprehensive early-return validation test
test('early return triggers ALL expected side effects', async () => {
const handler = loadHandler();
const context = createMockContext();
const req = createMockReq({ isCorrect: true });
await handler(context, req);
expect(context.res.status).toBe(400);
expect(mockTrackException).toHaveBeenCalled();
expect(mockCosmosCreate).not.toHaveBeenCalled();
expect(mockTrackEvent).not.toHaveBeenCalled();
});
Anti-Patterns
- Top-level
jest.mock() for module-scope side effects — leads to cached mocks across tests
- Asserting
context.done() was called — modern async functions should return, not context.done()
- Defaulting
body = {} in request helpers — hides the "missing body" edge case
- Skipping
{ virtual: true } — tests crash if mocked package isn't installed