如何Mock TypeORM的getCustomRepository?单元测试类构造函数依赖问题
getCustomRepository in Unit Tests I get it, mocking getCustomRepository when it’s called directly in a class constructor can feel like a puzzle—let’s break down exactly how to fix this with Jest, since that’s what you’re using in your test code. The goal here is to replace that database-dependent call with a mock that returns a fake repository, so your tests run fast without needing a real DB connection.
Step 1: Mock the typeorm Module’s getCustomRepository Function
Instead of trying to overwrite the function directly, we’ll use Jest’s module mocking to swap out getCustomRepository with a mock function. We’ll keep the rest of TypeORM’s exports intact so other parts don’t break.
Add this at the top of your test file (or inside the describe block):
import { getCustomRepository } from 'typeorm'; // Mock typeorm, preserving original exports except getCustomRepository jest.mock('typeorm', () => ({ ...jest.requireActual('typeorm'), getCustomRepository: jest.fn(), }));
Step 2: Create a Mock Repository & Wire It to the Mock Function
Next, inside your test case, we’ll define a fake UserRepository instance with our mocked findUser method, then tell getCustomRepository to return this fake instance when it’s called with UserRepository.
Here’s the updated test code:
import { Controller } from './Controller'; import { UserRepository } from './UserRepository'; import { User } from './User'; describe('User Tests', () => { // Reset mocks between tests to avoid cross-test contamination beforeEach(() => { jest.clearAllMocks(); }); it('should return the expected user', async () => { // 1. Create mock user data const mockUser = new User(); mockUser.id = 2; mockUser.name = 'Test User'; // 2. Create a fake repository with the mocked findUser method const mockUserRepo = { findUser: jest.fn().mockResolvedValue(mockUser), } as unknown as UserRepository; // 3. Make getCustomRepository return our fake repo (getCustomRepository as jest.Mock).mockReturnValue(mockUserRepo); // 4. Instantiate the Controller—its constructor will use our mock repo const controller = new Controller(); const result = await controller.init(); // 5. Verify everything works as expected expect(result).toBeDefined(); expect(result.id).toBe(2); expect(getCustomRepository).toHaveBeenCalledExactlyOnceWith(UserRepository); expect(mockUserRepo.findUser).toHaveBeenCalledExactlyOnceWith(1); }); });
Alternative Approach: Mock the UserRepository Class Directly
If you prefer, you can mock the entire UserRepository class so getCustomRepository returns an instance of this mocked class. Here’s how:
First, mock the UserRepository module at the top of your test file:
// Mock the UserRepository class jest.mock('./UserRepository', () => { const mockRepo = { findUser: jest.fn(), }; return { UserRepository: jest.fn(() => mockRepo) }; }); // Mock typeorm's getCustomRepository to return the mocked repo instance jest.mock('typeorm', () => ({ ...jest.requireActual('typeorm'), getCustomRepository: jest.fn((RepoClass) => RepoClass()), }));
Then adjust your test case:
import { Controller } from './Controller'; import { UserRepository } from './UserRepository'; import { User } from './User'; describe('User Tests', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should return the expected user', async () => { const mockUser = new User(); mockUser.id = 2; // Get the mocked repository instance const mockRepo = UserRepository(); mockRepo.findUser.mockResolvedValue(mockUser); const controller = new Controller(); const result = await controller.init(); expect(result).toEqual(mockUser); expect(mockRepo.findUser).toHaveBeenCalledWith(1); }); });
Why This Works
- By mocking
getCustomRepository, we ensure the Controller’s constructor never tries to connect to a real database—it gets our fake repository instead. - Jest’s mocking utilities let us track calls to both
getCustomRepositoryandfindUser, so we can verify exactly how our code interacts with these dependencies.
内容的提问来源于stack exchange,提问作者Nux

