0
# Provider Overriding
1
2
System for replacing providers, guards, pipes, filters, and interceptors with test doubles. This enables precise control over dependencies during testing, allowing developers to isolate components and create predictable test scenarios.
3
4
## Capabilities
5
6
### Override Methods
7
8
The TestingModuleBuilder provides specific methods for overriding different types of NestJS components.
9
10
```typescript { .api }
11
class TestingModuleBuilder {
12
/**
13
* Override a provider with a test double
14
* @param typeOrToken - The provider class or injection token to override
15
* @returns OverrideBy interface for specifying the replacement
16
*/
17
overrideProvider<T = any>(typeOrToken: T): OverrideBy;
18
19
/**
20
* Override a pipe with a test double
21
* @param typeOrToken - The pipe class or injection token to override
22
* @returns OverrideBy interface for specifying the replacement
23
*/
24
overridePipe<T = any>(typeOrToken: T): OverrideBy;
25
26
/**
27
* Override a guard with a test double
28
* @param typeOrToken - The guard class or injection token to override
29
* @returns OverrideBy interface for specifying the replacement
30
*/
31
overrideGuard<T = any>(typeOrToken: T): OverrideBy;
32
33
/**
34
* Override a filter with a test double
35
* @param typeOrToken - The filter class or injection token to override
36
* @returns OverrideBy interface for specifying the replacement
37
*/
38
overrideFilter<T = any>(typeOrToken: T): OverrideBy;
39
40
/**
41
* Override an interceptor with a test double
42
* @param typeOrToken - The interceptor class or injection token to override
43
* @returns OverrideBy interface for specifying the replacement
44
*/
45
overrideInterceptor<T = any>(typeOrToken: T): OverrideBy;
46
}
47
```
48
49
### OverrideBy Interface
50
51
Interface providing methods to specify how a component should be overridden.
52
53
```typescript { .api }
54
/**
55
* Interface for specifying component override strategies
56
*/
57
interface OverrideBy {
58
/**
59
* Replace with a specific value or instance
60
* @param value - The value to use as replacement
61
* @returns TestingModuleBuilder for method chaining
62
*/
63
useValue(value: any): TestingModuleBuilder;
64
65
/**
66
* Replace with a factory function result
67
* @param options - Factory configuration including function and dependencies
68
* @returns TestingModuleBuilder for method chaining
69
*/
70
useFactory(options: OverrideByFactoryOptions): TestingModuleBuilder;
71
72
/**
73
* Replace with an instance of a different class
74
* @param metatype - The class to instantiate as replacement
75
* @returns TestingModuleBuilder for method chaining
76
*/
77
useClass(metatype: any): TestingModuleBuilder;
78
}
79
80
/**
81
* Configuration options for factory-based overrides
82
*/
83
interface OverrideByFactoryOptions {
84
/**
85
* Factory function that creates the replacement instance
86
*/
87
factory: (...args: any[]) => any;
88
/**
89
* Optional array of dependencies to inject into the factory
90
*/
91
inject?: any[];
92
}
93
```
94
95
**Usage Examples:**
96
97
```typescript
98
import { Test, TestingModule } from "@nestjs/testing";
99
import { UsersService } from "./users.service";
100
import { DatabaseService } from "./database.service";
101
import { AuthGuard } from "./auth.guard";
102
import { LoggingInterceptor } from "./logging.interceptor";
103
104
describe("Provider Overriding", () => {
105
let module: TestingModule;
106
107
beforeEach(async () => {
108
// Override with useValue
109
const mockDatabaseService = {
110
findUser: jest.fn().mockResolvedValue({ id: 1, name: "Test User" }),
111
saveUser: jest.fn().mockResolvedValue({ id: 1 }),
112
};
113
114
module = await Test.createTestingModule({
115
providers: [UsersService, DatabaseService],
116
controllers: [UsersController],
117
})
118
.overrideProvider(DatabaseService)
119
.useValue(mockDatabaseService)
120
.compile();
121
});
122
123
it("should use mocked database service", async () => {
124
const usersService = module.get<UsersService>(UsersService);
125
const user = await usersService.findUser(1);
126
expect(user.name).toBe("Test User");
127
});
128
});
129
130
// Override with useClass
131
class MockAuthGuard {
132
canActivate() {
133
return true;
134
}
135
}
136
137
const moduleWithClassOverride = await Test.createTestingModule({
138
providers: [UsersService],
139
controllers: [UsersController],
140
})
141
.overrideGuard(AuthGuard)
142
.useClass(MockAuthGuard)
143
.compile();
144
145
// Override with useFactory
146
const moduleWithFactory = await Test.createTestingModule({
147
providers: [UsersService, DatabaseService, ConfigService],
148
})
149
.overrideProvider(DatabaseService)
150
.useFactory({
151
factory: (config: ConfigService) => ({
152
findUser: jest.fn(),
153
connection: config.getDatabaseUrl(),
154
}),
155
inject: [ConfigService],
156
})
157
.compile();
158
159
// Override interceptor
160
const moduleWithInterceptor = await Test.createTestingModule({
161
providers: [UsersService],
162
controllers: [UsersController],
163
})
164
.overrideInterceptor(LoggingInterceptor)
165
.useValue({
166
intercept: jest.fn((context, next) => next.handle()),
167
})
168
.compile();
169
```
170
171
### Advanced Override Patterns
172
173
**Partial Mocking:**
174
175
```typescript
176
// Override with partial implementation
177
const partialMockService = {
178
findUser: jest.fn().mockResolvedValue({ id: 1, name: "Test" }),
179
// Other methods will use original implementation or throw
180
};
181
182
const module = await Test.createTestingModule({
183
providers: [UsersService, DatabaseService],
184
})
185
.overrideProvider(DatabaseService)
186
.useValue(partialMockService)
187
.compile();
188
```
189
190
**Spy Integration:**
191
192
```typescript
193
// Create spy-enabled mock
194
const databaseServiceSpy = {
195
findUser: jest.fn(),
196
saveUser: jest.fn(),
197
deleteUser: jest.fn(),
198
};
199
200
const module = await Test.createTestingModule({
201
providers: [UsersService, DatabaseService],
202
})
203
.overrideProvider(DatabaseService)
204
.useValue(databaseServiceSpy)
205
.compile();
206
207
// Verify interactions
208
expect(databaseServiceSpy.findUser).toHaveBeenCalledWith(1);
209
```
210
211
**Token-based Overrides:**
212
213
```typescript
214
const DATABASE_TOKEN = Symbol("DATABASE_TOKEN");
215
216
const module = await Test.createTestingModule({
217
providers: [
218
UsersService,
219
{
220
provide: DATABASE_TOKEN,
221
useClass: DatabaseService,
222
},
223
],
224
})
225
.overrideProvider(DATABASE_TOKEN)
226
.useValue(mockDatabase)
227
.compile();
228
```
229
230
## Error Handling
231
232
Common override scenarios and error handling:
233
234
```typescript
235
// Handle missing dependencies
236
try {
237
const module = await Test.createTestingModule({
238
providers: [ServiceWithDependencies],
239
})
240
.overrideProvider(MissingDependency)
241
.useValue(mockDependency)
242
.compile();
243
} catch (error) {
244
// Handle compilation errors
245
}
246
247
// Override non-existent provider (will be ignored)
248
const module = await Test.createTestingModule({
249
providers: [UsersService],
250
})
251
.overrideProvider(NonExistentService) // This won't cause an error
252
.useValue(mockService)
253
.compile();
254
```
255
256
## Types
257
258
```typescript { .api }
259
import { TestingModuleBuilder } from "./testing-module.builder";
260
261
interface OverrideBy {
262
useValue: (value: any) => TestingModuleBuilder;
263
useFactory: (options: OverrideByFactoryOptions) => TestingModuleBuilder;
264
useClass: (metatype: any) => TestingModuleBuilder;
265
}
266
267
interface OverrideByFactoryOptions {
268
factory: (...args: any[]) => any;
269
inject?: any[];
270
}
271
```