きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

SQL Server データベースプロジェクトでSSDTの単体テスト機能を使わずに単体テストを行うアレコレ(主にデプロイ面の話)

前書き:SQL Server データベースプロジェクトはとても便利なのだけどSSDTの単体テスト機能は割と辛みがあるでNUnitとかxUnitとかでやりたい

いくつかの案件で、Visual StudioのSQL Server データベースプロジェクト*1(以下、DBプロジェクト)を用いてSQL Server上の各種オブジェクトの開発や構成管理を行っている。その開発・保守に際して、ストアドプロシージャや関数等のいわゆる自動単体テスト*2を行いたい要求があった。

SQL Server Data Tools(以下、SSDT)ではDBプロジェクトの単体テスト機能も提供しており、このSSDTの単体テスト機能はそれなりに便利で手軽ではある……のだが、私は現在ではあまり利用していない。

当初はそれなりに使ってはいたのだが、このSSDTの単体テスト機能の少々使い勝手が微妙な部分が、使い込むにしたがって許容できない判断するに至った。そのため現状はNUnitなどを用いてC#のコードからテスト用のデータベースに接続してテストするという手法に落ち着いている。

テスト対象オブジェクトのデータべースへのデプロイをどうするかという問題

単体テスト自体にSSDTは利用しないものの、DBプロジェクト内のソースをデータベースにデプロイするのは正直とても楽なので、その部分だけ無理やり(?)使っていた。

……いたのだが、紆余曲折あり*3、デプロイにもなるべく……少なくとも単体テストのプロジェクトから直接SSDTのクラスを参照するのは避けたいという思いが強くなった。

そこで代わりの方法を模索することにした。

達成したいポイントは以下だった。

  • SSDT関連のアセンブリに直接依存しない(プロジェクトからアセンブリ参照しない)
  • 事前に手動操作など挟まず単体テスト実行時に自動でDBプロジェクト内のソースを任意のデータベースにデプロイしたい

今回やってみたこと

前置きが長くなったが、これらを解決するために以下を試してみた。

  • 単体テストのセットアップ中に以下を行うことでDBにソースからオブジェクトをデプロイする
    • MSBuildをキックしてDBプロジェクトからdacpacを生成
    • SqlPackage.exeでデータベースに発行
  • MSBuild.exeと SqlPackage.exeを単体テストのSetupから実行するためのこれらのパスの解決を以下の方法で実施
    • 単体テストプロジェクトのビルド時、ビルド後イベントでVSのマクロ変数から拡張機能のインストールパスを取得、テキストファイルに書き出す
    • 単体テストのセットアップ時に前述のテキストファイルを読み出す

【2020.09.16追記】

コマンドラインツールそのものを実行するのではなく、NuGetで提供されているライブラリを利用して同等のことができるのを確認しました。 そのうちブログに書きます。

書きました!https://kiyokura.hateblo.jp/entry/2020/09/16/230331

コマンドラインツールによるビルドとデプロイ

DBプロジェクトはMSBuildでビルドすると普通にdacpacを生成するので、MSBuild.exeのパスさえわかれば特に問題はない。

これについては、先日のエントリ https://kiyokura.hateblo.jp/entry/2020/09/01/114511 を参照。

またSSDTで同時にインストールされるSqlPackage.exeを利用すればdacpacをデータベースへデプロイすることが可能で、これもSqlPackage.exeのパスさえわかれば問題ない。

こちらについては https://kiyokura.hateblo.jp/entry/2020/09/01/154255 を参照。

コマンドラインツールのパスの解決

少し考える必要がったのは、MSBuildやSqlPackgeの実行パスの取得方法である。 設定ファイルなどに個別に書いても良いが、当然実行環境ごとにパスは異なる可能性は当然あり(VS2017以降ではVSのバージョンだけでなくエディションによっても拡張機能インストールパスが異なる)、リポジトリの管理などでも別途考えることが出てくるので避けたかった。

そこで思いついたのがビルドイベント。ここであれでば $(MSBuildBinPath)$(DevEnvDir) などでビルドのタイミングでその環境で有効なパスが取得できるので、例えば以下のようにしてやればあとは単体テスト実行時に読んでやれば良い。

echo $(MSBuildBinPath)\msbuild.exe > "$(TargetDir)msbuildpath.txt"
echo $(DevEnvDir)Extensions\Microsoft\SQLDB\DAC\150\sqlpackage.exe > "$(TargetDir)sqlpackagepath.txt"

サンプルプロジェクト

これらを実際に組み込んだサンプルプロジェクトを以下に置いてたので、興味ある方は見ていただければ。

github.com

(ちなみに上記サンプルでは、データベースには SQL Server LocalDBを利用し、テスト実行時にその都度データベースインスタンスとDBを作り直してまっさらな状態でテストするようにしています)

*1:「Visual StudioのSQL Server データベースプロジェクトとは?」という方は https://docs.microsoft.com/ja-jp/sql/ssdt/project-oriented-offline-database-development?view=sql-server-ver15 や手前みそですが https://www.slideshare.net/kiyokura/sql-server-238387166/kiyokura/sql-server-238387166 など参照していただければと

*2:コードでテストを記述してテストランナーとかで実行するアレ

*3:書くと長くなりそうなので割愛