データベースを単体テストする方法

この記事は2021年4月7日にNishi Groverによって更新されました。

これまでの常として、もし単体テストとは何かと尋ねたなら、おそらくみごとなまでにバラバラの定義が返ってきたでしょう。

定義のなかには、たとえば「単体テストとはシステムの動作と機能をテストするためにコードを記述するプロセスである」といった非常に具体的なものから、「作ったばかりのものをテストすることだ」といった極端にあいまいなものまであります。 

しかし、単体テストが何であれ、もっと単体テストを行わなければならないという点には、誰もが同意するでしょう。単体テストは、技術の世界では、デンタルフロスを使用するようなものです。まだやっていなければ、始めるべきです。もうやっているとしても、十分ということはありません。

単体テストの基本

単体テストは自動化されたテストであり、たいていは開発者によって作成され、小さなコードコンポーネントを分離し、個別にテストします。

簡単なサンプルを考えてみましょう。2つの整数を加算する Add(int x, int y) というメソッドを作成するとします。

このメソッドの単体テストの1つとして、Add(2, 2)を呼び出した後、結果が4になることを検証します。それから別の単体テストとして、Add(2、 -2) を作成し、結果がゼロであることを検証します。

さまざまな単体テスト技法についてはこちらで詳しく学べます。

単体テストの特徴

  • 単体テストは自動化されます。単体テストフレームワークが検証を行い、成功/失敗という結果を返します。
  • 単体テストは細分化されます。Add() 関数はアプリケーション全体の中ではほんの小さなピースですが、これを個別にテストします。
  • 単体テストはターゲットを分離します。Add()をテストするのにさまざまなアプリケーションの設定や、ファイルや、グローバル変数をセットアップする必要はありません。
  • 単体テストは確定的です。Add(2, 2)は毎回確実に4を返します。
  • 単体テストは独立しています。以前に実行された他の単体テストに依存しておらず、順序という概念もありません。

単体テストは特定のガイドラインに従う必要があり、保守が容易でなければなりません。こちらでは、保守が容易な優れた単体テストの5つの要素について説明しています。

データベースの単体テストを行う理由

データベースはアプリケーション全体にとって重要なパーツです。データベースがテストの死角になってはいけません。 

アプリケーションのコードがファイルを開いたりデータベースに接続したりする場合、単体テストの細分化、分離、確定的の原則に反します。そこで、ファイルやデータベースをモック化して単体テストスイートから排除します。

では、データベースはどうやってテストしましょうか?そのために統合テストがあります。アプリケーションコードの隅々まで細心の注意を払ったうえで、データベースに関するすべてのテスト上の懸念を統合テストという大きなくくりの中に投げ入れます。

ところで、データベースは重要ではないのでしょうか?データベースは技術的製品の一部ではないのでしょうか?データベースを単体テストする価値はないのでしょうか?

データベースの単体テストはアプリケーションコードの単体テストほどには一般的ではありませんが、完全に実現可能です。これからその方法を説明します。

データベースを単体テストする方法

データベースのさまざまなテーブル、ビュー、トリガー等の作成スクリプトをソース管理します。すると、理論的には、データベースの空のインスタンスを取得し、テーブル等の要素の最小限のサブセットを独立して作成できることになります。これを出発点として、その後のあらゆる種類の動作をテストできます。

  • 単体テスト開始前にデータベースをきれいにするスクリプトを作成し、あらかじめ定義したデータのセットを投入し、テストを実行します。個々のテストを実行する前にこれらの処理を行うこともできます。実行は遅くなりますが、エラーはより起こりにくくなります。
  • 各テストを実行する前に、データベースが予期した状態にあることを確認し、テスト実行後にアサーションロジックを使用して状態を検証します。
  • ビューなどのモジュールからまだ参照されているオブジェクトを削除したり名前を変更したりしたことによる参照先の不足などの問題を見つけることもできます。 
  • 最後に、テスト実行後にデータベースが元の状態に復元されていることを確認します。

こちらでは採用するとよい習慣をいくつか紹介しています。

本来の性質として、データベースとアプリケーションコードにはいくつか重要な違いがあります。たとえば、データベースを既知の状態に設定すること、また開発者ごとにデータベースサーバーのコピーを持つことにいっそう注意を払うなど、いくつか新たにやるべきことがあります。しかし、隔たりは思うほどには大きくありません。

使用するツール

アプリケーションの単体テストフレームワークは豊富に存在し、自作する必要はありません。データベースの単体テストフレームワークはそれほど知られていませんが、やはり同じことが言えます。

検討を始めるにあたってチェックするべきツールがいくつかあります。

DbUnit
DbUnitはテストとテストの間にデータベースを既知の状態に設定します。DbUnitはデータベース駆動型プロジェクトに役立つJUnit拡張です。データベースのデータをインポート/エクスポートしたり、データが特定のセットと一致するかどうかを検証できます。
SQL Server
SQL Serverは機能スイートの一部としてデータベースの単体テストをサポートしています。テストプロジェクトを作成してSQL Serverの単体テストを直接追加し、操作できます。

SQL Test

SQL Testでは、トランザクション内でデータベース単体テストが実行されます。後で変更がロールバックされるため、クリーンアップコードは必要ありません。SQL TestはオープンソースのtSQLtフレームワークを使用します。 
DbFit
DbFitを利用すると、テスト駆動型データベース開発を実践できます。可読性と保守性の高いデータベースの単体テストコードを作成できます。
DB Test Driven
DBTDはデータベーステスト駆動型開発のためのツールです。管理が容易なデータベース単体テストを作成するのに役立つほか、コードカバレッジも計測できます。また、ビルドサーバーと統合して継続的インテグレーション機能を利用できます。

データベースの単体テストの特徴

アプリケーションの単体テストの前提条件は、すべてデータベースの単体テストでも満たすことができます。

  • 単体テストは自動化されます。コードの実行をスクリプト化するのと同じくらい容易にデータベースの操作のセットをスクリプト化できます。
  • 単体テストは細分化されます。個々のトリガー、ビュー、ストアドプロシージャ等の動作をテストできます。
  • 単体テストはターゲットを分離します。すべてのコンポーネントを再作成したりすべてのデータを投入することなく、データベースの必要な部分だけを扱うことができます。
  • 単体テストは確定的です。スキーマとデータをテストの一部としてセットアップすると、確定的な結果を得ることができます。
  • 単体テストは独立しています。必要なセットアップおよびティアダウンをテストの一部として管理すると、テストは他の依存関係を必要としません。

データベースの単体テストは可能なだけではなく、有意義です。データベースをテストの死角にしてはいけません。単体テストについてもっと知りたい方は、記事「The 7 Sins of Unit Testing」を参照してください。

この記事はErik Dietrichによるゲスト投稿です。Erik DietrichはDaedTech LLCの創業者であり、プログラマー、アーキテクト、ITマネジメントコンサルタント、著作者、科学技術者です。

(この記事は、開発元Gurock社の Blog 「How to Unit Test Your Database」2021年4月7日の翻訳記事です。)

eBook 公開中

Paul Gerrard著 効果的なテスト管理12の秘密 (日本語)

テスト計画やテスト管理に役立つ12のトピックを解説します。

詳細はこちら