liveBook · Manning

Module injection

As explained in The Art of Unit Testing 3e

Module injection is a dependency-injection technique in which a module receives or imports replaceable collaborators through its module boundary.

Module injection replaces a module’s dependency with a fake through a public module boundary. The fake keeps the original API while making tests more reliable and controllable. section 3.3 section 3.8

A module typically keeps original dependencies separately, routes calls through a replaceable dependency object, and exposes injection and reset functions. Tests inject a fake, exercise the module, then restore the originals. section 3.5 section 4.5.2

Faking a time dependency

A password verifier can depend on moment.js for the current day. A test injects a replacement whose day function returns Saturday, verifies the weekend error, and calls reset afterward. section 3.5 section 4.5

Listing 3.7 Abstracting the required dependencies
const originalDependencies = {                        #1
    moment: require(‘moment’),                        #1
};                                                    #1
 
let dependencies = { ...originalDependencies };       #2
 
const inject = (fakes) => {                           #3
    Object.assign(dependencies, fakes);
    return function reset() {                         #4
        dependencies = { ...originalDependencies };
    }
};
 
const SUNDAY = 0; const SATURDAY = 6;
 
const verifyPassword = (input, rules) => {
    const dayOfWeek = dependencies.moment().day();
    if ([SATURDAY, SUNDAY].includes(dayOfWeek)) {
        throw Error("It's the weekend!");
    }
    // more code goes here...
    // return list of errors found..
    return [];
};
 
module.exports = {
    SATURDAY,
    verifyPassword,
    inject
};
#1 Wrapping moment.js with an intermediary object
#2 The object containing the current dependency, either real or fake
#3 A function that replaces the real dependency with a fake one
#4 A function that resets the dependency back to the real one

Shows the dependency object, injection function, reset closure, and production code using the replaceable module. section 3.5

Listing 4.6 Testing with modular injection
const {
  verifyPassword,
  injectDependencies,
  resetDependencies,
} = require("./password-verifier-injectable");
 
describe("password verifier", () => {
  afterEach(resetDependencies);
 
  describe("given logger and passing scenario", () => {
    it("calls the logger with PASS", () => {
      let logged = "";
      const mockLog = { info: (text) => (logged = text) };
      injectDependencies({ log: mockLog });
 
      verifyPassword("anything", []);
 
      expect(logged).toMatch(/PASSED/);
    });
  });
});

Shows a logger fake injected into a password verifier and reset automatically after each test. section 4.5.3

Weigh the technique before adopting it:

  • Prefer controlled internal abstractions when third-party APIs might change; direct fakes can make many tests brittle. section 3.5
  • Reset injected dependencies after every test to prevent state leaking between tests. section 4.5.3
  • Choose function parameters, currying, factory functions, or constructor injection when exposing module injection is unsuitable. section 3.5 section 3.8

How The Art of Unit Testing 3e covers it

How deep it goes
Explains dependency indirection, public injection, resetting, examples, and brittleness, but stops short of framework-specific automation.
Examples
Demonstrates fake moment.js time and a mocked logger inside password-verifier tests.
What it assumes
Assumes basic JavaScript modules and testing, while teaching dependency replacement and test cleanup through small examples.
What you can do after
Apply it via public injection and reset functions to replace module dependencies and test controlled scenarios.
How it connects
Connects dependency injection with stubs, mock objects, third-party dependencies, and Ports and Adapters architecture.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Art of Unit Testing 3e. The section links point to the parts of the book it draws on.