テスト容易性のためのデザインパターン:Humble Objectパターンとは

テスト容易性の確保にかかわる責務設計、リファクタリングのためのデザインパターンに、Humble Objectパターン(Humbleオブジェクトパターン、質素なオブジェクトパターン)があります。

Humble Objectパターンは、ユニットテストデザインパターン集であるxUnit Test Patternsで定義されたものです。近年は書籍「単体テストの考え方/使い方」でテスト容易性を確保する基礎的技術として紹介され、認知が広がっています。

Humble Objectパターンは自動テスト、特にユニットテストをターゲットとします。大まかな概要として、以下を実施します。

  • 自動テストで実行しにくいオブジェクトを、「自動テストで実行できるオブジェクト」と、「自動テストで実行しにくいコード」に分離する
  • テストすべきロジックの責務をなるべく「自動テストで実行できるオブジェクト」に集中させる。

このHumble Objectパターンはいくつかバリエーションがあります。以下にまとめます。

Humble Objectを導入していないリファクタリング前のサンプル例

まず、Humble Objectを採用していない、自動テスト困難なサンプルを以下に示します。

このサンプルでは、自動テストでテスト対象オブジェクトをテストしたいものの、テストしたいロジックが、テスト実行を阻害するコードと強く結合しているため、テストできません。
これをHumble Objectを導入して改善します。

貧相なHumble Object(Poor Man's Humble Object)

Humbleオブジェクトパターンは、自動テストで実行できないオブジェクトを対象とするパターンです。
そのバリエーションの一つである貧相なHumble Objectは、テストしたいロジックを、自動テストで実行できるように別メソッドに抽出します。そしてテストは抽出した別メソッドを直接呼び出すことで、ロジックをテストします。

この貧相なHumble Objectは、メソッド抽出パターンといった小規模なリファクタリングしかできない状況下で、テスト容易性を確保したい場合に採用されます。

正当なHumble Object(True Humble Object)[テストを阻害するコードの分離]

正当なHumble Objectでは、自動テストを阻害するコードを、Humble Objectとして分離します。そしてテストしたいロジックを、テスト実行可能なオブジェクトとして実装します。
そしてテストでは、ロジックを担うオブジェクトを直接参照してテスト実行します。またプロダクトコードでは、Humble Objectを通してロジックを実行します。

この正当なHumble Objectは、レイヤドアーキテクチャで、レイヤごとにテスト容易性が異なる場合に採用しやすいです。典型例はGUIです。自動テストが困難なGUI定義・処理部分をHumble Objectとしてなるべく小さく分離・実装し、GUI部分でないロジックを自動テスト可能な形で実装する方針を取ります。

正当なHumble Object(True Humble Object)[HumbleなControllerを用意]

正当なHumble Objectのもう一つのバリエーションとして、責務設計におけるControllerをHumble Objectとして実装し、Humble Objectがテスト実行困難なオブジェクトと、テスト実行可能なオブジェクトを調停するパターンがあります。それによりテスト実行困難なオブジェクトとテスト実行可能なオブジェクトの結合を分離し、後者を自動テストでテストできるようにします。

このバリエーションでは、Humble Objectをテストが必要ないほど質素な責務として実装します。
このバリエーションは、MVCや、ヘキサゴナル・アーキテクチャといった、Controller専門のオブジェクトがドメインモデルやコアロジックを調停するアーキテクチャで親和性の高いものになります。