Dependency injection means giving a component the value, function, or object it needs from the outside instead of having it create or import that dependency itself. The immediate payoff is control: a password verifier can receive a chosen day rather than reading the real current day, making unusual cases predictable to test. Passing all dependencies in this way also makes a function pure when it has no side effects. section 3.3.1
Injection creates a seam: a place where a real dependency can later be replaced by a fake. A direct module import has no such replacement point unless the design changes. This is not limited to complex objects—an injected integer, function, or object can be a stub when the test controls its value or behavior. section 3.3.1 section 3.5
Choose an injection shape that fits the dependency and design:
- Pass a value when the dependency is simple state, such as the current day. section 3.3.1
- Pass a function when behavior must be supplied or special results and exceptions must be simulated. section 3.4.1
- Use partial application or a factory function to preconfigure dependencies and return a smaller function for normal use. section 3.4.2
- Pass an object through a constructor when an object-oriented design needs a collaborator such as a time provider. section 3.7.2
- Wrap imported modules in a dependency object only when module-level replacement is needed; provide a reset after tests replace the real dependency. section 3.5
Testing a weekend without waiting
A verifier that reads the clock internally cannot reliably reach a weekend case on demand. Instead, give it getDayFn and pass an alwaysSunday function in the test. The verifier then throws for Sunday every time. The same idea works with a FakeTimeProvider object whose getDay method returns Sunday. section 3.4.1 section 3.7.2
Manual injection is often enough. Factory functions can keep production construction in one place while tests construct objects directly with fakes. Framework-managed IoC or DI containers can configure constructor injection, but they are not required for effective tests and may add details that obscure what a test is setting up. section 3.7.2
Injection supports both stubs and mocks, but their testing purposes differ. A stub supplies controlled values or failures; a mock can verify an interaction, such as whether a logger received “PASSED.” In either case, the injected replacement only needs the part of the dependency interface that the component uses. section 3.7.3 section 4.3
Listing 3.6 Using a higher-order factory function
const SUNDAY = 0, . . . FRIDAY=5, SATURDAY = 6;
const makeVerifier = (rules, dayOfWeekFn) => {
return function (input) {
if ([SATURDAY, SUNDAY].includes(dayOfWeekFn())) {
throw new Error("It's the weekend!");
}
//more code goes here..
};
};
describe('verifier', () => {
test('factory method: on weekends, throws exceptions', () => {
const alwaysSunday = () => SUNDAY;
const verifyPassword = makeVerifier([], alwaysSunday);
expect(() => verifyPassword('anything'))
.toThrow("It's the weekend!");
});
A factory function shows dependency injection through partial application: rules and a day function are configured once, then the returned verifier accepts only input. section 3.4.2




















