Jest中如何模拟函数内部的函数调用?嵌套函数测试场景
Hey there! I see you're setting up tests for this nested function call chain (getBookingStateObject → getBookingStateButtons → linkButtons/sendEventButtons), but there's a small issue with your current mock setup—you're trying to mock individual function names as if they're separate modules, but all these functions are exported from the same ./bookingStates file. Let me help you fix that and build out proper test cases.
First, let's correct the mock approach. Since all functions come from the ./bookingStates module, we need to mock the entire module while specifying the behavior of each function we want to stub:
import { getBookingStateButtons, getBookingStateObject, linkButtons, sendEventButtons } from './bookingStates'; // Mock the entire bookingStates module jest.mock('./bookingStates', () => ({ __esModule: true, // Required if using ES modules getBookingStateButtons: jest.fn(), linkButtons: jest.fn(), sendEventButtons: jest.fn(), // Keep the real implementation of getBookingStateObject if we want to test it getBookingStateObject: jest.requireActual('./bookingStates').getBookingStateObject, }));
Now let's write tests for each layer of your function chain:
Test that getBookingStateObject calls getBookingStateButtons
This test verifies the top-level function correctly delegates to its dependency:
test('getBookingStateObject invokes getBookingStateButtons with the right parameters', () => { // Arrange: Prepare test data const mockBooking = { id: 'abc123', status: 'pending' }; // Act: Call the function we're testing getBookingStateObject(mockBooking); // Assert: Verify the dependency was called correctly expect(getBookingStateButtons).toHaveBeenCalledTimes(1); expect(getBookingStateButtons).toHaveBeenCalledWith(mockBooking); });
Test that getBookingStateButtons calls linkButtons and sendEventButtons
This test checks that the middle layer function properly uses its two child functions:
test('getBookingStateButtons calls both linkButtons and sendEventButtons appropriately', () => { // Arrange: Set up mock data and return values const mockState = 'confirmed'; const mockLinkBtns = [{ label: 'View Booking', url: '/bookings/abc123' }]; const mockEventBtns = [{ label: 'Cancel', eventType: 'booking_cancel' }]; linkButtons.mockReturnValue(mockLinkBtns); sendEventButtons.mockReturnValue(mockEventBtns); // Act: Call the function const result = getBookingStateButtons(mockState); // Assert: Verify dependencies were called, and result is correct expect(linkButtons).toHaveBeenCalledWith(mockState); expect(sendEventButtons).toHaveBeenCalledWith(mockState); expect(result).toEqual({ linkButtons: mockLinkBtns, sendEventButtons: mockEventBtns }); });
- Isolate tests: Add
jest.clearAllMocks()in abeforeEachblock to reset mock call counts/arguments between tests, so one test doesn't pollute another. - Mock selectively: Use
jest.requireActualto keep real implementations of functions you want to test, while only mocking their dependencies. - Validate return values: Don't just check if functions were called—verify they return the expected data too, to catch logic errors.
内容的提问来源于stack exchange,提问作者Sooraj

