Hexagonal testing

The testing model is bundled in the NPM package @tmorin/ceb-inversion-testing-core.

The isolation, provided by the Hexagonal Architecture, makes the testing of models easier. However, it leads to an annoying side effect: some tests, especially the functional ones, are duplicated among the adapters.

<ceb/> provides a testing library to prevent test duplication. The purpose is to define tests in the model which have to be executed in the adapters. So that, an adapter can validate the port implementation satisfy the model. The library leverages on the IoC container to let the adapter binds its implementation to the port.

The testing model

From the model point of view, i.e. the supplier, the suites are created using the TestSuiteBuilder and the scenarios with the TestScenarioBuilder.

import { assert } from "chai"
import { ModuleBuilder } from "@tmorin/ceb-inversion-core"
import {
  TestScenarioBuilder,
  TestSuiteBuilder,
} from "@tmorin/ceb-inversion-testing-core"

export const SuiteA = TestSuiteBuilder.get("ToEmphasize Port")
  .scenario(
    TestScenarioBuilder.get("Greeting target is emphasized")
      .configure((containerBuilder) => {
        containerBuilder.module(
          ModuleBuilder.get()
            .configure(function (registry) {
              registry.registerFactory("Greeting", (registry) => {
                // expect an adapter of the port "ToEmphasize"
                const toEmphasize =
                  registry.resolve<(value: string) => string>("ToEmphasize")
                // use the adapter to emphasize the target name
                return `Hello, ${toEmphasize("john doe")}`
              })
            })
            .build()
        )
      })
      .execute((container) => {
        // resolve the model artifact
        const text = container.registry.resolve<string>("Greeting")
        // validate the model artifact works as expected with the tested adapter
        assert.equal(text, "Hello, JOHN DOE!")
      })
      .build()
  )
  .build()

Mocha Implementation

The Mocha implementation of the testing model is bundled in the NPM package @tmorin/ceb-inversion-testing-mocha.

An implementation of the testing model is provided for Mocha.

From the provider point of view, the suites are executed using the MochaTestSuiteExecutorBuilder.

import { MochaTestSuiteExecutorBuilder } from "@tmorin/ceb-inversion-testing-mocha"
import { SuiteA } from "./hexagonal_testing-suite"
import { ModuleBuilder } from "@tmorin/ceb-inversion-core"

describe("ToEmphasize Adapter", function () {
  MochaTestSuiteExecutorBuilder.get(SuiteA)
    .configure((containerBuilder) => {
      containerBuilder.module(
        ModuleBuilder.get()
          .configure((registry) => {
            registry.registerValue("ToEmphasize", (value: string) =>
              value.toUpperCase()
            )
          })
          .build()
      )
    })
    .build()
    .execute()
})

Jest Implementation

The Jest implementation of the testing model is bundled in the NPM package @tmorin/ceb-inversion-testing-jest.

An implementation of the testing model is provided for Jest.

From the provider point of view, the suites are executed using the JestTestSuiteExecutorBuilder.

import { JestTestSuiteExecutorBuilder } from "@tmorin/ceb-inversion-testing-jest"
import { OnlyConfigureModule } from "@tmorin/ceb-inversion-core"
import { SuiteA } from "./hexagonal_testing-suite"

describe("ToEmphasize Adapter", function () {
  JestTestSuiteExecutorBuilder.get(SuiteA)
    .configure((containerBuilder) => {
      containerBuilder.module(
        OnlyConfigureModule.create(async function () {
          this.registry.registerValue("ToEmphasize", (value: string) =>
            value.toUpperCase()
          )
        })
      )
    })
    .build()
    .execute()
})