liveBook · Manning

Hexagonal architecture

As explained in The Art of Unit Testing 3e

An architectural pattern that isolates application logic behind ports and connects it to external systems through replaceable adapters.

Hexagonal architecture, also called Ports and Adapters or Onion architecture, keeps application code behind internal abstractions instead of importing uncontrolled dependencies directly. Replaceable adapters connect those abstractions to libraries and other external systems. section 3.5 section 5.2.2

The practical payoff is less brittle testing and safer replacement. A logging library or date library can change behind one adapter while application code and tests continue using a smaller API that the team controls. Direct mocking can solve legacy code problems, but it also binds tests to third-party APIs. section 3.5 section 5.2.2

Wrapping a date dependency

Instead of letting verifyPassword import moment directly, place moment behind a controlled dependency boundary. Tests can inject a small fake with a day function, verify the weekend behavior, and reset the dependency afterward. The test checks the internal contract rather than reproducing moment.js's entire API. section 3.5 section 3.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

A compact JavaScript listing shows a wrapped dependency, an injectable fake, and a reset function for restoring the original implementation. section 3.5

How The Art of Unit Testing 3e covers it

How deep it goes
Explains the dependency-boundary rationale and demonstrates injection, but stops short of a broader architectural implementation.
Examples
Uses moment.js around password verification and Winston logging as concrete cases for adapters and dependency isolation.
What it assumes
Assumes familiarity with dependencies and tests while illustrating dependency injection through a small JavaScript example.
What you can do after
Build it from scratch by placing replaceable dependencies behind small internal APIs and injecting fakes at test boundaries.
How it connects
Connects ports and adapters with dependency injection, mocking, testing, and direct dependency management.

Also explained in

Compare how 6 books explain hexagonal 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.