NestJS测试中Mock带@InjectRedisClient的Redis客户端问题
Let's break down how to resolve your Redis dependency issue and properly mock the other services you mentioned.
First: Resolve the REDIS_CLIENT_PROVIDER_0 Dependency Error
The root of your problem is that Nest can't find the mocked version of the Redis client injected with @InjectRedisClient('0'). The key here is to use the exact provider token that the decorator uses. Most Redis modules for Nest (like @nestjs-modules/ioredis) generate this token via a helper function called getRedisClientToken().
Here's how to correctly mock it:
import { Test } from '@nestjs/testing'; import { EmailSubscriptionService } from './email-service'; import { getRedisClientToken } from '@nestjs-modules/ioredis'; // Adjust import based on your Redis package describe('EmailSubscriptionService', () => { let service: EmailSubscriptionService; let mockRedisClient: jest.Mocked<any>; beforeEach(async () => { // Create a mock Redis client with the methods your service uses mockRedisClient = { get: jest.fn().mockResolvedValue(null), set: jest.fn().mockResolvedValue('OK'), del: jest.fn().mockResolvedValue(1), // Add any other Redis commands your service calls (e.g., hgetall, expire) }; const moduleRef = await Test.createTestingModule({ providers: [ EmailSubscriptionService, // Mock the Redis client using the correct token { provide: getRedisClientToken('0'), // Matches the '0' in @InjectRedisClient('0') useValue: mockRedisClient, }, // Add mocks for your other dependencies here (ConfigService, etc.) ], }).compile(); service = moduleRef.get<EmailSubscriptionService>(EmailSubscriptionService); }); it('should be defined', () => { expect(service).toBeDefined(); }); // Example test using the mocked Redis client it('should store a subscription in Redis', async () => { await service.subscribe('user@example.com'); expect(mockRedisClient.set).toHaveBeenCalledWith( 'subscription:user@example.com', expect.any(String), // Assuming you stringify the subscription data expect.any(Object) // Optional: If you set TTL or other options ); }); });
If you don't have access to getRedisClientToken(), you can directly use the token string from your error (REDIS_CLIENT_PROVIDER_0) as the provide value—though using the helper is more maintainable.
Handling Other Dependencies
Now let's cover how to mock the remaining services you mentioned:
1. ConfigService
Mock it by providing a useValue with a mocked get() method that returns the config values your service needs:
{ provide: ConfigService, useValue: { get: jest.fn((key: string) => { switch (key) { case 'EMAIL_FROM_ADDRESS': return 'no-reply@your-app.com'; case 'REDIS_TTL': return 86400; // Add all config keys your service uses } }), }, }
2. HttpService
Mock the HTTP client methods your service calls (e.g., post, get) to return predefined responses:
{ provide: HttpService, useValue: { post: jest.fn().mockResolvedValue({ data: { message: 'Email sent successfully' } }), // Mock other methods like get/put/delete if needed }, }
3. ManageSavedSearchService
If this is a custom service in your app, mock its public methods that EmailSubscriptionService relies on:
{ provide: ManageSavedSearchService, useValue: { getUserSavedSearches: jest.fn().mockResolvedValue([ { id: 1, query: 'latest news' } ]), // Add other methods your service calls }, }
Troubleshooting Tips
- Double-check all dependencies: Ensure every dependency of
EmailSubscriptionServiceis included in the testing module (either as a mock or real instance). - Verify mock methods: Make sure your mocks implement all the methods the service uses—missing methods will throw errors.
- Use spies if needed: If you need to track calls to a real service (unlikely in unit tests), use
jest.spyOn()instead of a full mock.
内容的提问来源于stack exchange,提问作者Joy

