ASP.NET Web API 2 の単体テストを実行する

Tom FitzMacken

完成したプロジェクトのダウンロード

このガイダンスとアプリケーションでは、Web API 2 アプリケーションの単純な単体テストを作成する方法を示します。 このチュートリアルでは、ソリューションに単体テスト プロジェクトを含め、コントローラー メソッドから返された値をチェックするテスト メソッドを記述する方法を示します。

このチュートリアルでは、ASP.NET Web API の基本的な概念を理解していることを前提としています。 入門チュートリアルについては、「ASP.NET Web API 2 の概要」を参照してください。

このトピックの単体テストは、意図的に単純なデータ シナリオに限定しています。 より高度なデータ シナリオの単体テストについては、「ASP.NET Web API 2 の単体テスト時に Entity Framework のモックを作成する」を参照してください。

チュートリアルで使用するソフトウェアのバージョン

このトピックの内容

このトピックは、次のセクションで構成されています。

前提条件

Visual Studio 2017 Community、Professional、または Enterprise Edition

コードをダウンロードする

完成したプロジェクトをダウンロードします。 ダウンロード可能なプロジェクトには、このトピック用、および ASP.NET Web API の単体テスト時における Entity Framework のモックの作成に関するトピック用の単体テスト コードが含まれています。

単体テスト プロジェクトを使用してアプリケーションを作成する

アプリケーションの作成時に単体テスト プロジェクトを作成するか、既存のアプリケーションに単体テスト プロジェクトを追加することができます。 このチュートリアルでは、単体テスト プロジェクトを作成するための両方の方法を示します。 このチュートリアルに従う際には、どちらの方法を使用してもかまいません。

アプリケーションの作成時に単体テスト プロジェクトを追加する

StoreApp という名前の新しい ASP.NET Web アプリケーションを作成します。

create project

[新しい ASP.NET プロジェクト] ウィンドウで、空のテンプレートを選択し、Web API のフォルダーとコア参照を追加します。 [単体テストの追加] オプションを選択します。 単体テスト プロジェクトには、StoreApp.Tests という名前が自動的に付けられます。 この名前は保持できます。

create unit test project

アプリケーションを作成すると、2 つのプロジェクトが含まれていることがわかります。

two projects

単体テスト プロジェクトを既存のアプリケーションに追加する

アプリケーションの作成時に単体テスト プロジェクトを作成しなかった場合は、いつでも追加できます。 たとえば、StoreApp という名前のアプリケーションが既にあり、単体テストを追加するとします。 単体テスト プロジェクトを追加するには、ソリューションを右クリックし、[追加][新しいプロジェクト] を選択します。

add new project to solution

左側のウィンドウで [テスト] を選択し、プロジェクトの種類として [Unit Test Project] (単体テスト プロジェクト) を選択します。 プロジェクトに StoreApp.Tests という名前を付けます。

add unit test project

ソリューションに単体テスト プロジェクトが表示されます。

その単体テスト プロジェクトで、元のプロジェクトへのプロジェクト参照を追加します。

Web API 2 アプリケーションを設定する

StoreApp プロジェクトで、Product.cs という名前の Models フォルダーにクラス ファイルを追加します。 このファイルの内容を次のコードに置き換えます。

using System;

namespace StoreApp.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

ソリューションをビルドします。

Controllers フォルダーを右クリックし、[追加][新しいスキャフォールディングされた項目] の順に選択します。 [Web API 2 コントローラー - 空] を選択します。

add new controller

コントローラー名を SimpleProductController に設定し、[追加] をクリックします。

specify controller

既存のコードを次のコードに置き換えます。 この例を簡略化するために、データはデータベースではなくリストに保存されます。 このクラスで定義されているリストは、実稼働データを表します。 このコントローラーには、Product オブジェクトのリストをパラメーターとして受け取るコンストラクターが含まれていることに注意してください。 このコンストラクターを使用すると、単体テスト時にテスト データを渡すことができます。 また、単体テストの非同期メソッドを示す 2 つの async メソッドもこのコントローラーに含まれています。 これらの非同期メソッドは、余分なコードを最小限に抑えるために Task.FromResult を呼び出して実装されていますが、通常、これらのメソッドには多くのリソースを使用する操作が含まれます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using StoreApp.Models;

namespace StoreApp.Controllers
{
    public class SimpleProductController : ApiController
    {
        List<Product> products = new List<Product>();        
           
        public SimpleProductController() { }

        public SimpleProductController(List<Product> products)
        {
            this.products = products;
        }

        public IEnumerable<Product> GetAllProducts()
        {
            return products;
        }

        public async Task<IEnumerable<Product>> GetAllProductsAsync()
        {
            return await Task.FromResult(GetAllProducts());
        }

        public IHttpActionResult GetProduct(int id)
        {
            var product = products.FirstOrDefault((p) => p.Id == id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }

        public async Task<IHttpActionResult> GetProductAsync(int id)
        {
            return await Task.FromResult(GetProduct(id));
        }
    }
}

GetProduct メソッドから、IHttpActionResult インターフェイスのインスタンスが返されます。 IHttpActionResult は Web API 2 の新機能の 1 つであり、単体テストの開発を簡素化します。 IHttpActionResult インターフェイスを実装するクラスは、System.Web.Http.Results 名前空間にあります。 これらのクラスは、アクション要求から返される可能性のある応答を表し、HTTP 状態コードに対応します。

ソリューションをビルドします。

これで、テスト プロジェクトを設定する準備ができました。

テスト プロジェクトに NuGet パッケージをインストールする

空のテンプレートを使用してアプリケーションを作成する場合、単体テスト プロジェクト (StoreApp.Tests) にはインストールされている NuGet パッケージは含まれません。 Web API テンプレートなどの他のテンプレートには、単体テスト プロジェクトにいくつかの NuGet パッケージが含まれています。 このチュートリアルでは、Microsoft ASP.NET Web API 2 Core パッケージをテスト プロジェクトに含める必要があります。

StoreApp.Tests プロジェクトを右クリックし、[NuGet パッケージの管理] を選択します。 パッケージをそのプロジェクトに追加するには、StoreApp.Tests プロジェクトを選択する必要があります。

manage packages

Microsoft ASP.NET Web API 2 Core パッケージを見つけてインストールします。

install web api core package

[NuGet パッケージの管理] ウィンドウを閉じます。

テストの作成

既定では、テスト プロジェクトには UnitTest1.cs という名前の空のテスト ファイルが含まれています。 このファイルには、テスト メソッドの作成に使用する属性が表示されます。 この単体テストでは、このファイルを使用することも、独自のファイルを作成することもできます。

UnitTest1

このチュートリアルでは、独自のテスト クラスを作成します。 UnitTest1.cs ファイルは削除できます。 TestSimpleProductController.cs という名前のクラスを追加し、コードを次のコードに置き換えます。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http.Results;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StoreApp.Controllers;
using StoreApp.Models;

namespace StoreApp.Tests
{
    [TestClass]
    public class TestSimpleProductController
    {
        [TestMethod]
        public void GetAllProducts_ShouldReturnAllProducts()
        {
            var testProducts = GetTestProducts();
            var controller = new SimpleProductController(testProducts);

            var result = controller.GetAllProducts() as List<Product>;
            Assert.AreEqual(testProducts.Count, result.Count);
        }

        [TestMethod]
        public async Task GetAllProductsAsync_ShouldReturnAllProducts()
        {
            var testProducts = GetTestProducts();
            var controller = new SimpleProductController(testProducts);

            var result = await controller.GetAllProductsAsync() as List<Product>;
            Assert.AreEqual(testProducts.Count, result.Count);
        }

        [TestMethod]
        public void GetProduct_ShouldReturnCorrectProduct()
        {
            var testProducts = GetTestProducts();
            var controller = new SimpleProductController(testProducts);

            var result = controller.GetProduct(4) as OkNegotiatedContentResult<Product>;
            Assert.IsNotNull(result);
            Assert.AreEqual(testProducts[3].Name, result.Content.Name);
        }

        [TestMethod]
        public async Task GetProductAsync_ShouldReturnCorrectProduct()
        {
            var testProducts = GetTestProducts();
            var controller = new SimpleProductController(testProducts);

            var result = await controller.GetProductAsync(4) as OkNegotiatedContentResult<Product>;
            Assert.IsNotNull(result);
            Assert.AreEqual(testProducts[3].Name, result.Content.Name);
        }

        [TestMethod]
        public void GetProduct_ShouldNotFindProduct()
        {
            var controller = new SimpleProductController(GetTestProducts());

            var result = controller.GetProduct(999);
            Assert.IsInstanceOfType(result, typeof(NotFoundResult));
        }

        private List<Product> GetTestProducts()
        {
            var testProducts = new List<Product>();
            testProducts.Add(new Product { Id = 1, Name = "Demo1", Price = 1 });
            testProducts.Add(new Product { Id = 2, Name = "Demo2", Price = 3.75M });
            testProducts.Add(new Product { Id = 3, Name = "Demo3", Price = 16.99M });
            testProducts.Add(new Product { Id = 4, Name = "Demo4", Price = 11.00M });

            return testProducts;
        }
    }
}

テストの実行

これで、テストを実行する準備が整いました。 TestMethod 属性でマークされているすべてのメソッドがテストされます。 [テスト] メニュー項目から、テストを実行します。

run tests

[テスト エクスプローラー] ウィンドウを開き、テストの結果を確認します。

test results

まとめ

これで、このチュートリアルが完了しました。 このチュートリアルのデータは、単体テスト条件に重点を置くために意図的に簡略化されています。 より高度なデータ シナリオの単体テストについては、「ASP.NET Web API 2 の単体テスト時に Entity Framework のモックを作成する」を参照してください。