テスト駆動開発(TDD)導入の4つのヒント

テスト駆動開発(TDD: Test-Driven Development)を簡潔に言えば、高いテストカバレッジを達成する必要最小限のコードを書くこと、これに尽きます。コードを書く前に要件のテストを作成し、テストが合格すれば即コードは完成とみなされます。なんだかとても良さそうに聞こえますが、では、組織に円滑にTDDを導入するにはどうすればよいのでしょうか?この記事では、TDD導入の利点を最大限にするためのヒントをご紹介します。

 

 

TDDの利点

TDDの一番の利点は、保守性が高くテスト可能なコードを作成するのに役立つことです。またTDDでは、機能を実装するために必要な、最小限のコードを作成することになるので、機能の肥大やコードの過剰な美化を防ぎます。正しいコードが書かれていることを検証するので、チームの効率性が高まり、間違った機能の構築に貴重な開発リソースを浪費することもなくなります。

TDDを実践するなら、必然的に組織的プラクティスとしてユニットテストを実施することになります。しかし、ユニットテスト自体を目的化してはいけません。ユニットテストは、あくまでテスト可能なコードを作成し、保守コストを削減し、技術的負債を低く抑えるのを支援するプラクティスです。堅固な回帰スイートを使用すれば、コード変更の結果として何かが壊れた場合に、すぐに知ることができます。

TDDへの関心が高まっている大きな理由として、多くの組織がアジャイル開発プラクティスに移行するいっぽう、既存のテストプラクティスはサイクル終盤の手動テストに大きく依存していることが認識されてきたという点が挙げられます。確かにエンドツーエンドのテストプラクティスが適切な場面もありますが、競争力を維持し必要なスピードで開発イノベーションを拡大するには、組織はテスト作業をシフトレフトする必要があります。 TDDは、健全なテストを基盤として開発プロジェクトを開始し、開発ライフサイクル全体を通じてソフトウェアの品質を実現することを保証するプロセスです。

TDD スペクトラム

現実的に言うと、純粋なTDDのビジョンに従ってソフトウェアを開発している人はごくわずかです。これにはいくつかの理由があります。現代のソフトウェア開発には、通常、ライブラリの統合、レガシーコードへの接続、既存の機能の拡張が伴います。多くの人々は完全に新しいコードを書くという贅沢な機会を持てないため、純粋なTDDは実用的ではありません。「TDDをやっている」と主張する多くの人々は、次のようなスペクトルのどこかに位置しています。

各組織はTDDの独自の課題を抱えていますが、Parasoftのお客様から最も多く寄せられる問題は、上記の3つの基本的なタイプに分けられます。しかし、スペクトルの範囲内には、多くのタイプのTDD実践者がいます。

TDD ニンジャ(TDD Ninja)

スペクトルの一端には、「黒帯」レベルでTDDをうまく実践している人々がいます。これらの人々は完全にTDDの原則に従っており、テストを書く前にはいっさい何も書きません。スケルトンはなく、定義もなく、まさに何もありません。そしてテストが成功するとすぐに終了します。結果として、コードは非常に効率的で保守性が非常に高くなります。TDDニンジャと話してみると、組織内のすべてのチームが自分たちほどうまくTDDを実践できているわけではないと認めるケースもよくあります。

実用的TDD派 (TDD Pragmatist)

スペクトルの次に来るのは、クラス、メソッドシグニチャなどを設計してから、それらの定義に対してテストを書く人々です。APIレベルでは、これはOpenAPI / SwaggerまたはWSDL定義の作成と同じです。これを実用的なTDDアプローチと呼びましょう。

このアプローチは、構造がはっきりし、明確さが大幅に増すので、多少は導入が容易です。すべてがまとめられ、チームの共同作業が容易になります。潜在的なトレードオフは、実用的TDD派は、TDDニンジャほど効率が高い最小限のコード設計を常に達成できるとは限らないことです。

レガシー向けTDD (TDD for Legacy)

できるものなら全面的にTDDを実践したいが、まっさらなコードから始めるという贅沢の余地はないという人も数多くいます。これらの人々は、レガシーコードを元に既存の機能を変更または拡張する際に、欠陥を再現したり、または期待動作をテストするためのテストを作成することがよくあります。

私たちの経験では、自分はTDDを実践していると認識している人の大部分が、スペクトルのこのあたりに位置します。テストとコードは密接にリンクされていますが、テストが必ずしもコードの前にあるわけではありません。それでも、コードの変更に先立ってテストがあります。

TDDもどき (TDD-ish)

TDDを自認する人たちのスペクトルの反対側の端には、テストとコード作成を並行で行う人たちがいます。TDDもどきの実践者にとっては、テストとコードが一緒にコミットされ、管理されている限りは、テスト駆動開発だという認識です。

テスト駆動開発(TDD)実践にあたっての4つのヒント

では、どのようにすればTDDをうまく導入できるでしょうか?TDDを成功させるには、以下の4つのヒントを参考にしてください。

1. レガシーコードにTDDを適用する

組織がテスト不可能なコードを受け継いでおり、技術的な負債を返済する能力を持たない場合、よくあるTDD実装の問題が浮上します。コードをリファクタリングするべきでしょうか?そうであれば、TDDを有意義かつ達成可能な方法で始めるのに、どれくらいのリファクタリングが必要でしょうか?

レガシーコードでTDDを始める必要がある場合、理想的なTDDを実装しようとしてもうまくいきません。受け継いだコードはテストが容易かどうかを念頭に置いて作成されたものではなく、元の作成者はもうチームにも、社内にすらいない場合があり、依存ライブラリが変更されている可能性などもあります。

レガシーコードが既にそこにあり、動いている場合、技術的な負債に関連するリスクは、新しい未テストの作業のリスクに比べると低いと考えられます。作成中の新しいコード、つまり既存のコードの変更にTDDを適用することで、リスクを最小限に抑え、技術的負債を増やさないようにします。

既存コードのテストに関する課題を克服する方法として、 Parasoft Jtestユニットテスト機能を使用して、有意義なテストを迅速に作成することができます。Parasoft Jtestは、レガシーコードとその依存関係を分析し、JUnitテストケースを作成し、既存のコードに必要な複雑なスタブ/モックの実装にかかる時間を短縮します。

2. マイクロサービスにTDDを適用する

マイクロサービスベースのアーキテクチャは、従来のアプリケーションスタックよりもはるかに依存性と複雑性が高く、テスト環境に高い変動性をもたらします。高度なモックやスタブが必要なため、マイクロサービスやその他の複雑なアーキテクチャに基づいたアプリケーションは、テストを作成するのが難しい場合があります。

いっぽうで、マイクロサービスベースのアーキテクチャは、TDDのベストプラクティスを非常に効率的に活用する機会を提供します。マイクロサービスをコンパイルユニットではなくユニットとみなすなら、実用的TDDアプローチは非常に有用になります。

APIレベルでTDDを適用する場合、APIはコントラクト(OpenAPI / Swagger、WSDL)で定義されます。Parasoft SOAtestなどのAPIテストソリューションでは、これらの定義に基づいてテストを自動的に作成できます。これで、定義に従って機能を開発し、SOAtestのテストが成功したら終了とする準備が整いました。

3. チームを戦力化する

一般的に、TDDは開発者中心のアクティビティとみなされています。通常、JUnitやNUnitなどのユニットテストフレームワークでテストを作成してカプセル化します。しかし、ほとんどの組織では、すべてのユースケースをカバーするだけの時間や開発者が不足しています。これは特に、プロジェクトに携わるメンバーの役割とスキルが混在している企業組織にとっては問題です。

上記のマイクロサービスの項目で説明したように、APIレベルでTDDプラクティスを活用すると、テスターの専門知識を活用してコントラクトに対するテストを定義できるため、技術リソースが限られているという問題に対処することができます。このアプローチでは、ビジネスアナリスト、テスター、その他の開発者以外の人員がTDDテストの作業に貢献できます。

Parasoft Virtualizeなどのサービス仮想化ソリューションを使用すると、機能をシミュレートするものをすぐに作成できます。コードを記述する前に、シミュレートされたバージョンに対してテストを作成して実行することもできます。

4. BDD で TDD を強化する

前述したように、TDDにはいくつもの利点がありますが、TDDを行うだけで要件を満たすコードが作成されるというわけではありません。TDDは、コードがテストでカバーされ、テストが合格することを保証するだけです。ここでビヘイビア駆動開発(BDD)の出番です。テストが成功するまでコードを記述するのではなく、ビヘイビアが実装されるまでコードを記述します。

過去にも、コードを書く前に機能フレームワークを定義しようとする試みがあったことは、注目に価します(デザインバイコントラクト(DbC)を覚えていらっしゃいますか?)。実際、BDDはこのようなアプローチを実装するための最新の試みです。BDD(またはDbC)では、テストまたはコードを作成する前に事前条件と事後条件を定義する必要があります。

BDDは、TDDを次のレベルに引き上げる機会を意味します。GherkinなどのBDD言語を使用している場合、Parasoft SOAtestはBDDの実装に伴う技術的障壁を低く抑えることができます。SOAtestはフィーチャーファイルから自動的にテストを作成し、通常は開発者リソースを必要とするグルーコードを書く際の技術的な複雑さを軽減します。

まとめ

テスト駆動開発が約束するメリットは、リーン開発の精神に基づくものです。TDDは効率的で、テスト可能で、保守可能なコードを作成するのに役立ちます。しかし、現実の状況によっては、TDDの採用が容易だとは限りません。Parasoftは、組織にとって実用的な方法でTDDプラクティスを採用し、開発/テストリソースを最大限に活用するのに役立ちます。ParasoftがTDDの実装にどのように役立つかの詳細については、こちらまでお問い合わせください。

(この記事は、開発元Parasoft社 Blog 「4 Tips for Adopting Test-Driven Development (TDD) in Your Organization」2018年8月16日の翻訳記事です。)

 

Parasoft Jtestについて

Java対応静的解析・単体テストツール Parasoft Jtest

Jtestは、テスト工数の大幅削減とセキュアで高品質なJavaシステムの開発を強力にサポートするJava対応テストツールです。1,000個以上のコーディング規約をもとにソースコードを静的に解析し、プログラムの問題点や処理フローに潜む検出困難なエラーを検出します。さらに、JUnitを用いた単体テストについて、作成、実行、テストカバレッジ分析、テスト資産の管理といった単体テストに係る作業をサポートし、単体テストの効率化を促進します。

 


Parasoft SOAtest/Virtualizeについて

 

APIのテスト自動化とサービス仮想化を1ツールで

SOAtest/Virtualizeは、APIの開発者/利用者に向けてテストの自動化とテスト環境の仮想化の2つの側面から開発を効率化します。SOAtest/Virtualizeは、APIのテストドライバーを提供し、開発中のAPIのテストを自動化する機能と、APIを利用するアプリケーションが必要とするAPIをスタブとして仮想化する機能を同梱して提供します。



Top