Visual Studio を使用する Azure Functions の開発

Visual Studio で、C# クラス ライブラリ関数を開発して、テストし、Azure にデプロイすることができます。 Azure Functions を初めて使用する場合は、「Azure Functions の概要」を参照してください。

Visual Studio には、関数の開発時の利点として次のようなことがあります。

  • ローカル開発用コンピューターで関数を編集、作成、および実行できます。
  • Azure Functions プロジェクトを Azure に直接発行し、必要に応じて Azure リソースを作成します。
  • C# 属性を使用して、C# コードで直接、関数のバインドを宣言できます。
  • コンパイル済み C# 関数を開発およびデプロイできます。 コンパイル済み関数では、C# スクリプト ベースの関数より優れたコールド スタート パフォーマンスが得られます。
  • Visual Studio 開発のすべての利点を得ながら、C# で関数をコーディングできます。

この記事では、Visual Studio を使って C# クラス ライブラリ関数を開発して Azure に発行する方法に関する詳細情報を提供します。 この記事を読む前に、Visual Studio 用の関数のクイックスタートに関するページを完了することをお勧めします。

特に明記されていない限り、ここで示す手順と例は Visual Studio 2022 のものです。 Visual Studio 2022 リリースの詳細については、リリース ノートまたはプレビュー リリース ノートを参照してください。

前提条件

  • Azure Functions Tools。 Azure Function Tools を追加するには、Visual Studio のインストールに Azure 開発ワークロードを含めます。 Visual Studio 2017 を使用している場合は、追加のインストール手順に従う必要があります。

  • Azure Storage アカウントなど、他の必要なリソースは、発行プロセス中にサブスクリプションに作成されます。

  • Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。

Azure Functions プロジェクトを作成する

Visual Studio の Azure Functions プロジェクト テンプレートを使用すると、Azure の関数アプリに発行できる C# クラス ライブラリ プロジェクトを作成できます。 関数アプリを使用すると、リソースの管理、デプロイ、スケーリング、および共有を容易にするための論理ユニットとして関数をグループ化できます。

  1. Visual Studio メニューで、 [ファイル]>[新規]>[プロジェクト] を選択します。

  2. [新しいプロジェクトの作成] の検索ボックスに「functions」と入力し、Azure Functions テンプレートを選択してから、 [次へ] を選択します。

  3. [新しいプロジェクトの構成] で、プロジェクトのプロジェクト名を入力し、 [作成] を選択します。 関数アプリ名は、C# 名前空間として有効である必要があります。そのため、アンダースコア、ハイフン、その他の英数字以外の文字は使用しないでください。

  4. [新しい Azure Functions アプリケーションの作成] 設定で、次の表の値を使用します。

    設定 説明
    .NET のバージョン .NET 6 この値により、Azure Functions ランタイムのバージョン 4.x でインプロセスを実行する関数プロジェクトが作成されます。 Azure Functions 1.x では、.NET Framework がサポートされます。 詳細については、「Azure Functions ランタイム バージョンをターゲットにする方法」をご覧ください。
    関数テンプレート HTTP トリガー この値は、HTTP 要求によってトリガーされる関数を作成します。
    ストレージ アカウント (AzureWebJobsStorage) ストレージ エミュレーター Azure の関数アプリにはストレージ アカウントが必要であるため、プロジェクトを Azure に発行する際に割り当てられるか、作成されます。 HTTP トリガーによって、Azure Storage アカウントの接続文字列が使用されることはありません。その他のすべてのトリガーの種類には、有効な Azure Storage アカウントの接続文字列が必要です。
    承認レベル Anonymous 作成される関数を、すべてのクライアントがキーを使用せずにトリガーできます。 この承認設定により、新しい関数のテストが容易になります。 キーと承認の詳細については、「承認キー」と HTTP と Webhook のバインドに関するページをご覧ください。

    Azure Functions プロジェクトの設定

    [承認レベル][匿名] に設定していることを確認します。 関数の既定のレベルを選択した場合、関数エンドポイントにアクセスする要求で、関数キーを提示する必要があります。

  5. [作成] を選択して、関数プロジェクトと HTTP トリガー関数を作成します。

Azure Functions プロジェクトを作成した後、プロジェクト テンプレートを使用して C# プロジェクトを作成し、Microsoft.NET.Sdk.Functions NuGet パッケージをインストールし、ターゲット フレームワークを設定します。 新しいプロジェクトには次のファイルが含まれます。

  • host.json:Functions のホストを構成できます。 これらの設定は、ローカルでの実行時と Azure での実行時の両方に適用されます。 詳細については、host.json のリファレンスを参照してください。

  • local.settings.json:関数をローカルで実行するときに使用される設定を保持します。 Azure で実行している場合、これらの設定は使用されません。 詳細については、「ローカル設定ファイル」を参照してください。

    重要

    local.settings.json ファイルにはシークレットを含めることができるため、それをプロジェクト ソース管理から除外する必要があります。 このファイルの [出力ディレクトリにコピー] 設定が [新しい場合はコピーする] に設定されていることを確認します。

詳細については、「関数クラス ライブラリ プロジェクト」を参照してください。

ローカル設定

Azure の関数アプリで実行する場合、関数に必要な設定はアプリ設定に安全に保存されます。 ローカル開発中は、これらの設定はその代わりに local.settings.json ファイルの Values オブジェクトに追加されます。 local.settings.json ファイルには、ローカルの開発ツールによって使用される設定も格納されます。

local.settings.json には接続文字列などのシークレットが含まれている場合があるため、リモート リポジトリには絶対に格納しないようにしてください。 ローカル設定の詳細については、「ローカル設定ファイル」を参照してください。

プロジェクトを発行しても、Visual Studio では local.settings.json の設定が自動的にアップロードされません。 これらの設定が Azure の Function App にも確実に存在するようにするには、プロジェクトを発行した後にそれらをアップロードします。 詳細については、「Function App の設定」を参照してください。 ConnectionStrings コレクション内の値は発行されません。

コードを使用して、Function App の設定値を環境変数として読み取ることもできます。 詳細については、「環境変数」を参照してください。

ローカル開発用のプロジェクトを構成する

Functions ランタイムでは内部的に Azure Storage アカウントを使用します。 HTTP と Webhook 以外のすべてのトリガーの種類について、Values.AzureWebJobsStorage キーを有効な Azure Storage アカウントの接続文字列に設定します。 関数アプリでは、プロジェクトに必要な AzureWebJobsStorage 接続設定に Azure エミュレーターを使用することもできます。 エミュレーターを使用するには、AzureWebJobsStorage の値を UseDevelopmentStorage=true に設定します。 この設定は、デプロイ前に実際のストレージ アカウント接続文字列に変更します。 詳細については、ローカル ストレージ エミュレーターに関するページを参照してください。

ストレージ アカウントの接続文字列を設定するには、次のようにします。

  1. Azure Portal のストレージ アカウントに移動します。

  2. [アクセス キー] タブの [セキュリティ + ネットワーク] の下にある key1接続文字列をコピーします。

  3. プロジェクトで、local.settings.json ファイルを開き、コピーした接続文字列に AzureWebJobsStorage キーの値を設定します。

  4. 前の手順を繰り返し、関数に必要なその他のすべての接続について、Values 配列に一意のキーを追加します。

プロジェクトに関数を追加する

C# クラス ライブラリ関数では、関数で使用されるバインドはコードで属性を適用することで定義されます。 提供されているテンプレートから関数トリガーを作成する場合は、トリガー属性が適用されます。

  1. ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、 [追加]>[新しいアイテム] の順に選択します。

  2. [Azure 関数] を選択し、クラスの [名前] を入力して [追加] を選択します。

  3. トリガーを選択し、バインドのプロパティを設定して、[追加] を選択します。 次の例は、Queue storage トリガー関数を作成する場合の設定を示しています。

    Queue storage トリガー関数を作成する

    その後、Azurite ストレージ エミュレーターか、プロビジョニングされた Azure ストレージ アカウントを参照するかを選択するように求められます。

    このトリガーの例では、QueueStorage という名前のキーと共に接続文字列を使用します。 local.settings.json ファイルに保存されているこのキーでは、Azurite エミュレーターまたは Azure ストレージ アカウントを参照します。

  4. 新しく追加されたクラスを確認します。 FunctionName 属性で属性が指定された静的 Run() メソッドを確認します。 この属性は、メソッドが関数のエントリ ポイントであることを示します。

    たとえば、次の C# クラスは基本的な Queue storage トリガー関数を表します。

    using System;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    
    namespace FunctionApp1
    {
        public static class Function1
        {
            [FunctionName("QueueTriggerCSharp")]
            public static void Run([QueueTrigger("myqueue-items", 
                Connection = "QueueStorage")]string myQueueItem, ILogger log)
            {
                log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
            }
        }
    }
    

バインド固有の属性は、エントリ ポイント メソッドに指定された各バインド パラメーターに適用されます。 属性ではパラメーターとしてバインド情報を取ります。 前の例では、Queue storage トリガー関数を示す QueueTrigger 属性が最初のパラメーターに適用されています。 キュー名および接続文字列の設定名は、パラメーターとして QueueTrigger 属性に渡されます。 詳細については、Azure Functions での Azure Queue ストレージのバインドに関する記事を参照してください。

上記の手順を使用して、複数の関数を Function App プロジェクトに追加します。 プロジェクト内の各関数で異なるトリガーを使用できますが、1 つの関数には 1 つのトリガーのみを使用する必要があります。 詳しくは、「Azure Functions でのトリガーとバインドの概念」をご覧ください。

バインドの追加

トリガーと同じように、入力バインドと出力バインドも、バインド属性として関数に追加されます。 以下のように、関数にバインドを追加します。

  1. プロジェクトをローカル開発用に構成したことを確認します。

  2. バインドの参照記事でバインド固有のNuGet パッケージ要件を見つけることで、特定のバインドに適したNuGet拡張パッケージを追加します。 たとえば、Event Hubs トリガーのパッケージ要件については、Event Hubs のバインドの参照記事を参照してください。

  3. パッケージ マネージャー コンソールで次のコマンドを使用して、特定のパッケージをインストールします。

    Install-Package Microsoft.Azure.WebJobs.Extensions.<BINDING_TYPE> -Version <TARGET_VERSION>
    

    この例では、<BINDING_TYPE> をバインド拡張機能に固有の名前に置き換え、<TARGET_VERSION>3.0.0-beta5 などの特定のバージョンのパッケージに置き換えます。 有効なバージョンは、NuGet.org の個々のパッケージ ページに記載されています。Functions ランタイム 1.x または 2.x に対応する主要なバージョンは、バインデイングのリファレンス記事に示されています。

  4. バインドが必要なアプリ設定がある場合は、ローカル設定ファイルValues コレクションに追加します。

    この関数では、ローカルで実行するときにこれらの値を使用します。 関数が Azure の Function App で実行される場合は、Function App の設定が使用されます。

  5. 適切なバインド属性をメソッド シグネチャに追加します。 次の例では、キュー メッセージによって関数がトリガーされ、出力バインドによって、同じテキストの新しいキュー メッセージが別のキューに作成されます。

    public static class SimpleExampleWithOutput
    {
        [FunctionName("CopyQueueMessage")]
        public static void Run(
            [QueueTrigger("myqueue-items-source", Connection = "AzureWebJobsStorage")] string myQueueItem, 
            [Queue("myqueue-items-destination", Connection = "AzureWebJobsStorage")] out string myQueueItemCopy,
            ILogger log)
        {
            log.LogInformation($"CopyQueueMessage function processed: {myQueueItem}");
            myQueueItemCopy = myQueueItem;
        }
    }
    

    Queue Storage への接続は、AzureWebJobsStorage 設定から取得されます。 詳しくは、特定のバインドの参照記事をご覧ください。

Functions でサポートされるバインドを網羅した一覧については、「サポートされるバインディング」を参照してください。

関数をローカルで実行する

Azure Functions Core Tools を使用すると、ローカルの開発用コンピューター上で Azure Functions プロジェクトを実行できます。 Functions プロジェクトをデバッグするために F5 キーを押すと、ローカル Functions ホスト (func.exe) が起動し、ローカル ポート (通常は 7071) をリッスンします。 呼び出し可能な関数エンドポイントが出力に書き込まれるので、それらのエンドポイントを関数のテストに使用できます。 詳細については、「Azure Functions Core Tools の操作」を参照してください。 Visual Studio から初めて関数を起動すると、これらのツールをインストールするよう求めるメッセージが表示されます。

Visual Studio のデバッグ モードで関数を開始するには:

  1. F5 キーを押す。 メッセージが表示されたら、Visual Studio からの要求に同意し、Azure Functions Core (CLI) ツールをダウンロードしてインストールします。 また、ツールで HTTP 要求を処理できるように、ファイアウォールの例外を有効にすることが必要になる場合もあります。

  2. プロジェクトを実行して、デプロイ済みの関数をテストする場合と同じようにコードをテストします。

    Visual Studio をデバッグ モードで実行すると、想定どおりにブレークポイントにヒットします。

Visual Studio を使用したテストに関する詳細なシナリオについては、「関数のテスト」を参照してください。

Azure に発行する

Visual Studio から発行する場合は、次の 2 つのデプロイ方法のいずれかが使用されます。

次の手順を使用して、プロジェクトを Azure の Function App に発行します。

  1. ソリューション エクスプローラーで、プロジェクトを右クリックし、 [発行] を選択します。 [ターゲット]で、[Azure] を選択し、[次へ] を選択します。

    発行ウィンドウのスクリーンショット。

  2. [特定のターゲット][Azure Function App (Windows)] を選択して、Windows で実行される関数アプリを作成し、[次へ] を選択します。

    ターゲットを指定した発行ウィンドウのスクリーンショット。

  3. [Function Instance] (関数インスタンス) で、[新しい Azure 関数を作成] を選択します。

    関数アプリ インスタンスを新規に作成する際のスクリーンショット。

  4. 次の表に示されている値を使用して、新しいインスタンスを作成します。

    設定 説明
    名前 グローバルに一意の名前 新しい関数アプリを一意に識別する名前。 この名前をそのまま使用するか、新しい名前を入力します。 有効な文字は、a-z0-9- です。
    サブスクリプション 該当するサブスクリプション 使用する Azure サブスクリプション。 このサブスクリプションを承諾するか、ドロップダウン リストから新しいものを選択します。
    リソース グループ リソース グループの名前 関数アプリを作成するリソース グループ。 ドロップダウン リストから既存のリソース グループを選択するか、または [新規] を選択して新しいリソース グループを作成します。
    プランの種類 従量課金 従量課金プランで実行される関数アプリにプロジェクトを発行する場合は、関数アプリの実行に対してのみお支払いください。 他のホスティング プランでは、コストが高くなります。
    場所 App Service の場所 最寄りのリージョンまたは関数がアクセスする他のサービスの近くのリージョン内の [場所] を選択します。
    Azure Storage 汎用ストレージ アカウント Functions の共通言語ランタイムでは、Azure ストレージ アカウントが必要です。 [新規] を選択して汎用ストレージ アカウントを構成します。 または、ストレージ アカウントの要件を満たす既存のアカウントを選択することもできます。

    App Service 作成ダイアログのスクリーンショット。

  5. [作成] を選択して、関数アプリとその関連リソースを Azure で作成します。 リソース作成のステータスがウィンドウの左下に表示されます。

  6. [Functions instance] (関数インスタンス) で、[Run from package file] (パッケージ ファイルから実行します) に必ずチェックを入れてください。 関数アプリは、Zip Deploy を使用して、Run-From-Package モードが有効な状態でデプロイされます。 Zip Deploy は、関数プロジェクトの推奨されるデプロイ方法であり、パフォーマンスが向上します。

    プロファイル作成完了のスクリーンショット。

  7. [完了] を選択し、[発行] ページで [発行] を選択して、プロジェクト ファイルを含むパッケージを Azure の新しい関数アプリにデプロイします。

    デプロイが完了すると、Azure の関数アプリのルート URL が [発行] タブに表示されます。

  8. [発行] タブの [ホスティング] セクションで、[Azure portal で開く] を選択します。 これにより、Azure portal に新しい関数アプリの Azure リソースが開きます。

    発行成功メッセージのスクリーンショット。

Function App の設定

Visual Studio では、プロジェクトを発行するときにこれらの設定が自動的にアップロードされることはありません。 local.settings.json に追加したすべての設定は、Azure の関数アプリにも追加する必要があります。

Azure の関数アプリに必要な設定をアップロードする最も簡単な方法は、[ホスティング] セクションの横にある 3 つの点を展開し、プロジェクトが正常に発行された後に表示される [Azure App Service の設定を管理する] リンクを選択することです。

[発行] ウィンドウの設定

このリンクを選択すると、Function App の [アプリケーションの設定] ダイアログが表示され、ここで新しいアプリケーション設定を追加したり、既存の設定を変更したりできます。

アプリケーションの設定

[ローカル] には local.settings.json ファイルの設定値が表示され、 [リモート] には Azure の Function App の現在の設定値が表示されます。 新しいアプリ設定を作成するには、 [設定の追加] を選択します。 [ローカルから値を挿入する] リンクを使用して、設定値を [リモート] フィールドにコピーします。 [OK] を選択すると、保留中の変更がローカル設定ファイルと Function App に書き込まれます。

Note

既定では、local.settings.json ファイルはソース管理にチェックインされません。 これは、ソース管理からローカル関数プロジェクトを複製するときに、プロジェクトに local.settings.json ファイルがないことを意味します。 この場合、 [アプリケーション設定] ダイアログが期待どおりに動作するように、プロジェクトのルートに local.settings.json ファイルを手動で作成する必要があります。

以下のいずれかの方法を使用して、アプリケーション設定を管理することもできます。

Remote Debugging

関数アプリをリモートでデバッグするには、プロジェクトのデバッグ構成を発行する必要があります。 また、Azure の関数アプリでリモート デバッグを有効にする必要もあります。

このセクションでは、リリース構成を使用して関数アプリに既に発行していることを前提としています。

リモート デバッグに関する考慮事項

  • 運用環境のサービスでは、リモート デバッグはお勧めしません。
  • マイ コードのみのデバッグを有効にしている場合は、無効にします。
  • リモート デバッグ時、ブレークポイントで長時間停止させることは避けてください。 数分以上停止しているプロセスは、応答していないプロセスと見なされ、Azure によりシャットダウンされます。
  • デバッグ中は、サーバーから Visual Studio にデータが送信されるため、帯域幅の使用料に影響が及ぶ可能性があります。 帯域幅使用料については、 Azure 料金計算ツールを参照してください。
  • リモート デバッグは、関数アプリで 48 時間後に自動的に無効になります。 48 時間後に、リモート デバッグを再度有効化する必要があります。

デバッガーをアタッチします。

デバッガーをアタッチする方法は、実行モードによって異なります。 分離ワーカー プロセス アプリをデバッグする場合、現在はリモート デバッガーを別の .NET プロセスにアタッチする必要があり、その他にもいくつかの構成手順が必要です。

完了したら、リモート デバッグを無効にする必要があります。

Functions ホストを使用してインプロセスで実行されている関数アプリにリモート デバッガーをアタッチするには:

  • [発行] タブの [ホスティング] セクションで省略記号 (...) を選択し、[Attach debugger (デバッガーのアタッチ)] を選択します。

    Visual Studio からデバッガーをアタッチ中のスクリーンショット。

Visual Studio は関数アプリに接続し、まだ有効になっていない場合はリモート デバッグを有効にします。 また、アプリのホスト プロセスにデバッガーを見つけてアタッチします。 この時点で、関数アプリを通常どおりにデバッグできます。

リモート デバッグの無効化

コードのリモート デバッグが完了したら、Azure portal でリモート デバッグを無効にする必要があります。 リモート デバッグは、忘れた場合でも 48 時間後に自動的に無効になります。

  1. プロジェクトの [発行] タブで、[ホスティング] セクションで省略記号 (...) を選択し、[Azure Portal で開く] を選択します。 このアクションにより、プロジェクトのデプロイ先の Azure portal で関数アプリが開きます。

  2. 関数アプリの、[設定][構成] を選択し、[全般設定] を選択し、[リモート デバッグ]オフ に設定して、[保存] を選択して [続行] を選択します。

関数アプリの再起動後、リモート プロセスにリモート接続できなくなります。 同じタブを Azure portal で使用して、Visual Studio の外部でリモート デバッグを有効できます。

関数の監視

関数の実行を監視するための推奨される方法は、Function App を Azure Application Insights と統合することです。 Azure Portal で Function App を作成する場合、この統合は、既定で自動的に行われます。 ただし、Visual Studio の発行中に Function App を作成する場合は、Azure で Function App の統合は実行されません。 Application Insights を関数アプリに接続する方法については、「Application Insights との統合を有効にする」を参照してください。

Application Insights を使用した監視の詳細については、「Azure Functions を監視する」を参照してください。

関数のテスト

このセクションでは、C# の関数アプリ プロジェクトを Visual Studio で作成し、xUnit を使った実行とテストを行う方法について説明します。

Visual Studio で C# を使って Azure Functions をテストする

セットアップ

環境を設定するには、関数を作成し、アプリをテストします。 次の手順では、テストをサポートするために必要なアプリと関数を作成できます。

  1. 新しい関数アプリを作成して Functions という名前を付けます
  2. テンプレートから HTTP 関数を作成して MyHttpTrigger という名前を付けます。
  3. テンプレートからタイマー関数を作成して MyTimerTrigger という名前を付けます。
  4. ソリューションで xUnit テスト アプリを作成して Functions.Tests という名前を付けます。 既定のテスト ファイルを削除します。
  5. NuGet を使用して、テスト アプリから Microsoft.AspNetCore.Mvc への参照を追加します
  6. Functions.Tests アプリから Functions アプリを参照します。

テスト クラスの作成

これでプロジェクトが作成されたため、自動テストの実行に使用するクラスを作成できます。

各関数は、ILogger のインスタンスを取得して、メッセージ ログを処理します。 テストによっては、メッセージをログに記録しないことも、ログの実装方法に対する懸念がないこともあります。 その他のテストは、テストを渡すかどうかを判断するために、ログに記録されたメッセージを評価する必要があります。

テストの間に評価するメッセージの内部リストを保持する ListLogger という名前の新しいクラスを作成します。 必要な ILogger インターフェイスを実装するには、クラスにスコープが必要です。 次のクラスでは、ListLogger クラスに渡すテスト ケースのスコープがモックされます。

Functions.Tests プロジェクトに NullScope.cs という名前の新しいクラスを作成し、次のコードを入力します。

using System;

namespace Functions.Tests
{
    public class NullScope : IDisposable
    {
        public static NullScope Instance { get; } = new NullScope();

        private NullScope() { }

        public void Dispose() { }
    }
}

次に、Functions.Tests プロジェクトに ListLogger.cs という名前の新しいクラスを作成し、次のコードを入力します。

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;

namespace Functions.Tests
{
    public class ListLogger : ILogger
    {
        public IList<string> Logs;

        public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;

        public bool IsEnabled(LogLevel logLevel) => false;

        public ListLogger()
        {
            this.Logs = new List<string>();
        }

        public void Log<TState>(LogLevel logLevel,
                                EventId eventId,
                                TState state,
                                Exception exception,
                                Func<TState, Exception, string> formatter)
        {
            string message = formatter(state, exception);
            this.Logs.Add(message);
        }
    }
}

ListLogger クラスは、ILogger インターフェイスによって縮小される次のメンバーを実装します。

  • BeginScope:スコープがログにコンテキストを追加します。 この場合、テストで NullScope クラスの静的インスタンスをポイントするだけで、テストを機能させることができます。

  • IsEnabled:既定の値 false が指定されます。

  • Log:このメソッドは、指定された formatter 関数を使用してメッセージの書式を設定してから、結果のテキストを Logs コレクションに追加します。

Logs コレクションは List<string> のインスタンスであり、コンストラクターで初期化されます。

次に、Functions.Tests プロジェクトに LoggerTypes.cs という名前の新しいファイルを作成し、次のコードを入力します。

namespace Functions.Tests
{
    public enum LoggerTypes
    {
        Null,
        List
    }
}

この列挙型は、テストで使用されるロガーの種類を指定します。

次に、Functions.Tests プロジェクトに TestFactory.cs という名前の新しいクラスを作成し、次のコードを入力します。

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using System.Collections.Generic;

namespace Functions.Tests
{
    public class TestFactory
    {
        public static IEnumerable<object[]> Data()
        {
            return new List<object[]>
            {
                new object[] { "name", "Bill" },
                new object[] { "name", "Paul" },
                new object[] { "name", "Steve" }

            };
        }

        private static Dictionary<string, StringValues> CreateDictionary(string key, string value)
        {
            var qs = new Dictionary<string, StringValues>
            {
                { key, value }
            };
            return qs;
        }

        public static HttpRequest CreateHttpRequest(string queryStringKey, string queryStringValue)
        {
            var context = new DefaultHttpContext();
            var request = context.Request;
            request.Query = new QueryCollection(CreateDictionary(queryStringKey, queryStringValue));
            return request;
        }

        public static ILogger CreateLogger(LoggerTypes type = LoggerTypes.Null)
        {
            ILogger logger;

            if (type == LoggerTypes.List)
            {
                logger = new ListLogger();
            }
            else
            {
                logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
            }

            return logger;
        }
    }
}

TestFactory クラスは、次のメンバーを実装します。

  • Data:このプロパティは、サンプル データの IEnumerable コレクションを返します。 キー値のペアは、クエリ文字列に渡される値を表します。

  • CreateDictionary:このメソッドは、キー/値ペアを引数として受け取り、クエリ文字列値を表す QueryCollection を作成するために使用する新しい Dictionary を返します。

  • CreateHttpRequest:このメソッドは、指定されたクエリ文字列パラメーターで初期化される HTTP 要求を作成します。

  • CreateLogger:このメソッドは、ロガーの種類に応じて、テストに使用されるロガー クラスを返します。 ListLogger は、テストで評価に使用できるログ記録されたメッセージを追跡します。

最後に、Functions.Tests プロジェクトに FunctionsTests.cs という名前の新しいクラスを作成し、次のコードを入力します。

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Xunit;

namespace Functions.Tests
{
    public class FunctionsTests
    {
        private readonly ILogger logger = TestFactory.CreateLogger();

        [Fact]
        public async void Http_trigger_should_return_known_string()
        {
            var request = TestFactory.CreateHttpRequest("name", "Bill");
            var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
            Assert.Equal("Hello, Bill. This HTTP triggered function executed successfully.", response.Value);
        }

        [Theory]
        [MemberData(nameof(TestFactory.Data), MemberType = typeof(TestFactory))]
        public async void Http_trigger_should_return_known_string_from_member_data(string queryStringKey, string queryStringValue)
        {
            var request = TestFactory.CreateHttpRequest(queryStringKey, queryStringValue);
            var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
            Assert.Equal($"Hello, {queryStringValue}. This HTTP triggered function executed successfully.", response.Value);
        }

        [Fact]
        public void Timer_should_log_message()
        {
            var logger = (ListLogger)TestFactory.CreateLogger(LoggerTypes.List);
            new MyTimerTrigger().Run(null, logger);
            var msg = logger.Logs[0];
            Assert.Contains("C# Timer trigger function executed at", msg);
        }
    }
}

このクラスで実装されるメンバーは次のとおりです。

  • Http_trigger_should_return_known_string:このテストは、HTTP 関数へのクエリ文字列値 name=Bill を含む要求を作成し、予期された応答が返されることを確認します。

  • Http_trigger_should_return_string_from_member_data:このテストは、xUnit 属性を使用して、HTTP 関数にサンプル データを提供します。

  • Timer_should_log_message: このテストは、ListLogger のインスタンスを作成してタイマー関数に渡します。 関数が実行されると、予期されたメッセージが存在することを確認するためにログがチェックされます。

テストでアプリケーションの設定にアクセスする場合は、モックされた環境変数の値を持つ IConfiguration インスタンスを関数に挿入できます。

テストの実行

テストを実行するには、テスト エクスプローラーに移動し、[すべてのテストをビューで実行] を選択します。

Visual Studio で C# を使って Azure Functions をテストする

テストのデバッグ

テストをデバッグするには、テストにブレークポイントを設定し、テスト エクスプローラーに移動して、[実行]> [前回の実行をデバッグする] の順に選択します。

Azure Functions tools with Visual Studio 2017

Azure Functions Tools は、Visual Studio 2017 以降の Azure 開発ワークロードで使用できます。 Visual Studio 2017 では、Azure 開発ワークロードによって Azure Functions Tools が別個の拡張機能としてインストールされます。 Visual Studio 2019 以降では、Azure Functions ツールの拡張機能が Visual Studio の一部として更新されます。

Visual Studio 2017 のインストールを更新する場合、Azure Functions Tools の最新バージョンを使用していることを確認してください。 以下のセクションでは、Visual Studio 2017 の Azure Functions Tools 拡張機能を確認し、必要に応じて更新する方法について説明します。

Visual Studio 2017 でツールのバージョンを確認する

  1. [ツール] メニューの [拡張機能と更新プログラム] を選択します。 [インストール済み]>[ツール] メニューを展開し、 [Azure Functions と Web ジョブ ツール] を選択します。

    Functions ツールのバージョンを確認する

  2. インストールされている [バージョン] をメモし、このバージョンをリリース ノートに記載されている最新バージョンと比較します。

  3. インストールされているバージョンが古い場合は、次のセクションの説明に従って Visual Studio でツールを更新します。

Visual Studio のツールを更新する

  1. [拡張機能と更新プログラム] ダイアログで、 [更新プログラム]>[Visual Studio Marketplace] を展開し、 [Azure Functions と Web ジョブ ツール][更新] の順に選択します。

    Functions ツールのバージョンを更新する

  2. ツールの更新プログラムがダウンロードされたら、 [閉じる] を選択し、Visual Studio を閉じて、VSIX インストーラーを使用してツールの更新をトリガーします。

  3. VSIX インストーラーで、 [変更] を選択してツールを更新します。

  4. 更新が完了したら、 [閉じる] を選択して Visual Studio を再起動します。

次のステップ

Azure Functions Core Tools の詳細については、「Azure Functions Core Tools の操作」を参照してください。

.NET クラス ライブラリとしての関数の開発の詳細については、「Azure Functions C# 開発者向けリファレンス」を参照してください。 この記事は、Azure Functions でサポートされる各種バインドを宣言するための属性の使用例にもリンクしています。