「消化するテスト」から「価値を生むテスト」へ──業務の複雑さに適したテスト方針(前編)
はじめに
「テスト項目を“消化”することが目的になってしまい、本来の品質向上や業務課題の解決につながらない」「業務の複雑さに対して、テストや設計がうまく噛み合わず、現場で手戻りや不安が絶えない」――そんな悩みを感じている方も多いのではないでしょうか。
- テストケースはたくさん作っているのに、現場の“やった感”ばかりが残り、肝心の不具合や業務上のリスクが減らない
- 業務が複雑化しているのに、従来通りのテスト方針や設計のままで、現場の困りごとが解消されない
- 「なぜこのテストをやるのか?」が曖昧なまま、テスト項目を“消化”すること自体が目的化してしまう
こうした課題は、現場の開発者だけでなく、プロジェクトを推進する上位層や事業部の方々にとっても大きな悩みとなっています。
本記事(前編)では、こうした現場の課題を踏まえつつ、書籍『ドメイン駆動をはじめよう ソフトウェアの実装と事業戦略を結びつける実践技法』[1]で紹介されている、業務の複雑さに応じた実装方法とテスト方針の適切な組合せを紹介します。後編では、私自身がテスト支援の業務を通じて直面した「相性の悪い組合せ」と、そこから見えてきた改善の方向についても触れる予定です。
業務とデータの複雑さから考える実装方法の選択
まずは「業務の複雑さ」と「実装方法」の組合せについて考えます。『ドメイン駆動をはじめよう』では業務ロジックの実装方法を以下の4つに分類しています。
- トランザクションスクリプト
- アクティブレコード
- ドメインモデル
- イベント履歴式ドメインモデル
これらは単なる技術的な好みで選ぶものではなく、業務ルールの複雑さとデータ構造の複雑さという2つの軸から適切なスタイルを選ぶことが重要です。
単純な業務ルールに適したスタイル
業務ルールが比較的単純な領域(たとえば、他システムとの連携や補完的な処理)では、トランザクションスクリプトやアクティブレコードが適しています。
データ構造が単純な場合は、処理を手続き的に記述するトランザクションスクリプトがシンプルで扱いやすく、保守性も高くなります。
一方で、データ構造が複雑な場合には、データと振る舞いを1つのクラスにまとめるアクティブレコードの方が自然に表現できます。
なお、これらはいずれも書籍『エンタープライズアプリケーションアーキテクチャパターン』[2]で紹介されているパターンです。また書籍とは別にPatterns of Enterprise Application Architecture - Martin Fowler's Bliki (ja)で概要を知ることができます。
複雑な業務ルールに適したスタイル
一方、業務ルールが複雑な領域では、ドメインモデルやイベント履歴式ドメインモデルのような、より構造化されたアプローチが求められます。
ドメインモデルは、ロジックとデータの両方を一体化させた、事業活動を表現するオブジェクトモデルのことで、ドメイン駆動設計の手法を用いて組み立てることができます。業務の概念やルールをコード上に明示的に表現することで、複雑な振る舞いを整理しやすくします。
特に、金銭を扱う処理や監査記録が必要な業務、あるいはシステムの利用状況を後から分析したいケースでは、イベント履歴式ドメインモデルが有効です。これは、状態の変化をイベントとして記録することで、過去の履歴を正確に再現できるという特長があります。
実装スタイルに応じたテスト方針の選び方
実装スタイルが異なれば、業務ロジックの配置や責務の分担も変わります。それに伴い、効果的なテストの基本方針も変わってきます。ここでは、代表的な3つのテスト方針と、それぞれに適した実装スタイルの組合せを紹介します。
実装スタイルとテスト方針は密接に関係しています。構造に合ったテスト戦略を選ぶことで、テストの効果と開発体験の両方を高めることができます。
ピラミッド型:ドメインモデルに最適
ピラミッド型テストは、ユニットテストを基盤に、上位レイヤーのテスト(統合テストやE2Eテスト)を段階的に積み上げる構成です。
この方針は、ドメインモデルやイベント履歴式ドメインモデルのように、業務ロジックが 集約(Aggregate)や値オブジェクト(Value Object) として明確に分離されている場合に特に効果を発揮します。
ユニットテストでドメインの振る舞いを直接検証できるため、テストの粒度と責務が一致しやすく、保守性も高くなります。
ダイヤモンド型:アクティブレコードに適している
ダイヤモンド型テストは、ユニットテストとE2Eテストの比重を抑え、統合テストを中心に据えるスタイルです。テスティングトロフィーとしても知られているのがこの形ではないでしょうか。
アクティブレコードを用いた実装では、業務ロジックがサービス層とモデル層にまたがって実装されることが多く、単体でのテストが難しいケースがあります。
このような構成では、複数のコンポーネントをまとめて検証する統合テストが最も効果的です。ダイヤモンド型は、そうした構造に自然にフィットします。
逆ピラミッド型:トランザクションスクリプトに適している
逆ピラミッド型テストは、E2Eテストを中心に据え、ユニットテストの比重を小さくする構成です。
トランザクションスクリプトは、業務ロジックが単一の手続きとして記述され、レイヤー構造も比較的単純です。そのため、E2Eテストで全体の振る舞いを検証するのが最も効率的です。
アイスクリームコーンと呼ばれるアンチパターンと同じ形ですが、この場合はユニットテストで細かく分割するよりも、シナリオベースでの検証が現実的かつ効果的なケースが多くなります。
おわりに
今回ご紹介したように、業務とデータの複雑さに応じて実装スタイルとテスト方針を選ぶことは、設計の整合性とテストの効果を高めるうえで非常に重要です。これらの組合せが適切でない場合、複雑な業務ロジックが複数に分散してしまい保守性が悪くなったり、大量のテストを実施しているにもかかわらず、肝心の品質向上につながらないといった問題が発生しやすくなります。
後編では、私が実際に支援している現場で直面した「相性の悪い組合せ」の実例を紹介し、そこからどのように改善の糸口を見出そうとしているのかをお話しします。

NTT DATA公式アカウントです。 技術を愛するNTT DATAの技術者が、気軽に楽しく発信していきます。 当社のサービスなどについてのお問い合わせは、 お問い合わせフォーム nttdata.com/jp/ja/contact-us/ へお願いします。
Discussion