VSTS の ビルドで SQL Server LocalDB を使ってテストしたい

わざわざ SQL DB 立てたくなかったので LocalDB 使えるか調べたメモ

こんなのを見つけたので出来そうな感じでしたが、
Database Integration Tests in Visual Studio Team Services and Cake Build | Trailmax Tech


で教えてくれたので特に何もせず接続文字列だけ LocalDB にして動かす形にしてます。

VSTS の Hosted VSTS2017 agent で動かすので、LocalDB は既定のインスタンス(MSSQLLocalDB)で問題無しですね。*1
ちなみにバージョンは 2018/05/07 時点で SQL Server 2016 SP1 でした。

Database の作成や初期データは、ビルド実行前に *.bacpac で投入する方法にしてます。
※個別のテスト用のデータは、テスト毎に投入しますが不変なデータも毎回入れるのは面倒なので事前に用意する形です。

bacpac は、ざっくりいうと スキーマとデータをパッケージングしたファイルです。
Data-tier Applications | Microsoft Docs
これがあれば、SQL DB / SQL Server にデータベース(スキーマとデータ)丸ごとインポートすることが出来ます。

bacpac のインポートは、PowerShell でさくっと出来ます。
このスクリプトVSTS のビルド定義 PowerShell から呼び出すだけ。

$dir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

Add-Type -Path "$dir\Microsoft.SqlServer.Dac.dll"
$srv = New-Object Microsoft.SqlServer.Dac.DacServices "Data Source=(localdb)\MSSQLLocalDB;Pooling=False"
$package = [Microsoft.SqlServer.Dac.BacPackage]::Load("$dir\Sample.bacpac")
$srv.ImportBacpac($package, "Sample")

気を付ける点は、Microsoft.SqlServer.Dac.dll 読むのには、依存関係にある dll も読み込める場所に配置しとく必要がある位ですかね。
今回は、
NuGet Gallery | Microsoft.SqlServer.DacFx.x64 140.3881.1
を使いましたが、Microsoft.SqlServer.Dac.dll を含む6つの dll を *.ps1 と同じ場所に置いてます。

接続文字列は 環境変数 にあればそこから取る形にしてます。*2
VSTS で実行する時は、ビルド定義で接続文字列埋め込む形です。

using System;
using System.Data.SqlClient;
using Xunit;
using Dapper;
using Xunit.Abstractions;

public class UnitTest1 {
  [Fact]
  public void Test1() {
    var connstr = Environment.GetEnvironmentVariable("VSTS_CONNSTR")
      ?? @"普段使う接続文字列";
    using (var conn = new SqlConnection(connstr)) {
      Assert.Equal("Test", conn.ExecuteScalar<string>(
          @"select Name from Table1 where Id = 1"));
    }
  }
}

VSTS の ビルドで 環境変数の設定はこちらを参考に。
Build variables | Microsoft Docs
指定する接続文字列はこんな感じで。

Server=(localdb)\MSSQLLocalDB;Initial Catalog=Sample;Pooling=false

*1:他から繋がないし

*2:開発環境でのテストは、普通の SQL Server 使いたい