Azure Cosmos DBのエミュレーターをAzureDevOpsのビルドパイプラインで利用してCI/CDする

# 問題

プロジェクトをAzure DevOpsでマネージしていて、そのプロジェクトでAzure Cosmos DBを利用していて、なおかつビルドする度にAzure Cosmos DB SKDを利用したコードの機能テストをしたい。でも、クラウド上の実際のAzure Cosmos DBをテストに使ってお金を使いたくない。

# 解決

Azure Cosmos DB Emulator を新たにビルドパイプラインのタスクに加えて、テストの際にEmulatorに対して操作を行って機能テストをします。Azure Cosmos DB EmulatorのDockerのイメージをインスタンスとしてスタートすることが出来ます。テストを.runsettings 設定ファイルから得た値を使って接続するようにすると、ビルド中にDockerインスタンスでホストされているAzure Cosmos DB Emulatorに繋いて各種機能を実行して検証することが出来るようになります。

# 準備 marketplace.visualstudio.comからAzure Cosmos DB Emulator 拡張を探す

(1) marketplace.visualstudio.comに行って

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/24a9df50-84fa-e49f-02a2-1be41ebb748a.png' width='996' />

(2) cosmos で検索して

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/641660fb-e66a-9c54-9e6b-59d5008438c2.png' width='850' />

(3) 拡張のページに行って

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/fd8b9d15-64e6-88ef-04c3-e1f4430a3f9e.png' width='894' />

(4) Get it free でインストールする。自分の組織（organization）に加える。

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/2307300e-8d46-1059-0df0-4430d6541dfb.png' width='1002' />

これで、Azure DevOps上で、ビルドパイプラインにAzure Document DB Emulator のタスクを加える準備が出来ました。
その前に、テストプロジェクトの方で、runsettings からAzure Document DBへの接続情報を得るように準備します。

# プロジェクトにエミュレーターへ接続するための 。」.runsettings ファイルを加える

[サンプルテストプロジェクト (GitHub)](https://github.com/yoshiwatanabe/code-examples/tree/master/azure/AzureCosmosTest)

サンプルのプラットフォームは.NET Core。利用しているAzure Cosmos DB SDKは2019年1月現在まだPreviewの[SDK v3.0](https://github.com/Azure/azure-cosmos-dotnet-v3)です（GitHubで公開されてるオープンソースのパッケージ。fluentスタイルでクエリを作成出来たりするので可読性が上がりそうです）

[サンプル .runsettings ファイル （GitHub）](https://github.com/yoshiwatanabe/code-examples/blob/master/azure/AzureCosmosTest/test/UnitTestProject1/TestSettings/CosmosDbTest.runsettings)　

ご自分のプロジェクトにこのファイルをコピペします。

```
﻿<RunSettings>
  <TestRunParameters>
    <Parameter name="endpoint" value="https://localhost:8081" />
    <Parameter name="authKey" value="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" />
    <Parameter name="database" value="ToDoListTest" />
    <Parameter name="collection" value="ItemsTest" />
  </TestRunParameters>
</RunSettings>
```

この .runsettings ファイルの ```authKey``` の値は「そのまま」使います。通常はこういったKeyデータをソースに記録してしまうのがご法度ですが、これはエミュレータの「よく知られた値」で、これ以外の値だとエミュレーターとつながりません。

endpoint もこのままでいいです。ビルドの時に、そのビルド環境（エージェント環境）に対応したendpointの値で「上書き」します（後述）。

.runsettingsの拡張子さえあれば、ファイル本体の名前は適当でオッケーです。プロジェクト内での .runsettings ファイルの保存場所もどこでも構いません。

テストプロジェクトは .runsettings で定義されている```TestRunParameters```の値を使ってAzure Cosmos DB に接続しないといけません。[テストコードのサンプル (GitHub)](https://github.com/yoshiwatanabe/code-examples/blob/master/azure/AzureCosmosTest/test/UnitTestProject1/UnitTest1.cs)　を見てください。

以下が .runsettings から設定を読み込んでいる部分です。

```
 ・・・省略
        [TestInitialize()]
        public void Initialize()
        {
            string endpoint = TestContext.Properties["endpoint"].ToString();
            string authKey = TestContext.Properties["authKey"].ToString();
            repository = new Repository(endpoint, authKey);
        }
　・・・省略
```

こうすることで、endpointとauthKeyの簡単に変更できるようにします。実際にはauthKeyはEmulator独特の値を使用するので、endpointの値しか変更する必要はありません。

# ビルドパイプラインを作成する

以下が、Azure Cosmos DB Emulator と Visual Studio Test のタスクを含んだビルドパイプラインです。他の部分はプロジェクトによりけるの部分です。このようにAgent Jobを定義します。

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/f2a31c3a-970e-5520-cb5a-2b51347b53aa.png' width='1184' />

Azure Cosmos DB Emulator のタスク設定は得にありません。

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/c3e2ac3c-71d7-e343-9da3-0c069e924bd7.png' width='1077' />

ポートマッピングでDocker でホストされている Azure Cosmos DB Emulator が外界との接続にポート8081を使っているのが確認できます。（先の .runsettings ファイル上の endpoint もポート番号は8081でしたね）

Visual Studio Testのタスクは2か所の重要な設定項目があります。

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/b880e6cd-8869-0f76-a92f-51552b700307.png' width='1086' />

まずは自分のプロジェクト内での .runsettings ファイルを示します。次に```endpoint```の項目を別の値で上書きします。この際、「別の値」とは、Azure Cosmos DB Emulator のendpointの値になりますが、その値は```CosmosDbEmlator.Endpoint```という環境変数から得ることが出来ます。

# 実行してみる

以下が、ビルド実行の結果です

<img src='https://qiita-image-store.s3.amazonaws.com/0/103139/3cf5d2c5-f5fd-700e-733b-4ce9510122b8.png' width='796' />

エミュレータがスタートした後、機能テストが成功したのが分かります。PULL REQUEST毎にビルドをして、機能テストをパスしないコードの侵入を防ぐことも出来ます（というかベストプラクティス）

# まとめ

Azure Cosmos DB を利用するプロジェクトはエミュレータをビルドパイプラインに組み込むことで簡単に、安く、機能テストすることが出来るので便利。