はじめに
今回は、ユニットテストを行うためのフレームワークをASP.NET Core
に導入したかったので、xUnit
というフレームワークを導入してみた。
この記事はその時の備忘録となる。
環境
Windows 11 Professional
Visual Studio 2022 Community
ASP.NET Core 8.0
xUnitとは
- xUnit
https://xunit.net/
xUnit
は、.NETアプリケーション用のテストフレームワークで、単体テストを効率的に実行するためのツール。xUnit
は、テストの作成や実行を簡単にし、コードの品質を向上させることを目的としている。
主な特徴として、アサーション、テストの分類、依存関係の管理などがあり、これにより、開発者は容易にテストケースを定義し、テストを自動化できる。
xUnitを選んだ理由について
Microsoftの.NET でのテストのページを見ると、
- xUnit
- NUnit
- MSTest
などがあげられている。
この中で、xUnit
を選んだ理由としては、現在最も使われているテストフレームワークのようだからだ。
下記を見たところ、xUnit
が一番使われているそうなので、じゃあまあこれでという感じで使ってみることにした。
- おすすめの単体テストフレームワークを探してみる(C#編:2024年6月)
https://parasoft.techmatrix.jp/dottest-unittest-202306
導入
例によって、ASP.NET Core
のWebアプリケーションが既にプロジェクトとしてある状態で始める。
下記のリポジトリは、以前よりサンプルとして使っており、今回もここに導入をしてみることにする。
https://github.com/katsuobushiFPGA/ASPCoreNetSample
プロジェクトの作成
1. ASP.NET Coreのプロジェクトを起動する
2. ソリューションを右クリック→「追加」→「新しいプロジェクト」を選択する
3.「xUnitテストプロジェクト」を選択し、「次へ」
4. プロジェクト名を入力して、「次へ」
ここでは、[テスト対象のプロジェクト名].Tests
という名前にしている。
下記のドキュメントでも、そのような命名だったため、それに倣って作成している。
https://learn.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-with-dotnet-test
5. 「追加情報」はデフォルトのままで「作成」を選択
6. ソリューションエクスプローラーにて、作成した「WebApplication2.Tests」が表示されていることを確認する
依存関係の参照/インストール
プロジェクト参照の追加
1. 「依存関係」を右クリック、「プロジェクト参照の追加」を選択する
2. 「WebApplication2(テスト対象のプロジェクト)」を選択し、「次へ」
3. 「依存関係」→「プロジェクト」に「WebApplication2(テスト対象のプロジェクト)」が入っていることを確認
ライブラリのインストール
Moqのインストール
- プロジェクトを右クリック、「NuGetパッケージの管理」を選択する
- 「
Moq
」をインストールする - インストール完了後、依存関係に 「
Moq
」が入っていることを確認
xUnitのインストール
xUnit
系はプロジェクト作成時にインストール済みのため不要。
ただし、最新バージョンより古いので、最新バージョンを使う必要があればアップデートをする。
テストの作成
今回はお試しで、Controllers/HomeController.cs
のテストを作成してみる。
テストプロジェクトのディレクトリ構成について
ディレクトリ構成のベストプラクティス的なものが見つからなかったので、ChatGPT
に聞いてみた。
ASP.NET CoreのプロジェクトでxUnitを使ってコントローラのテストを行う場合、一般的なディレクトリ構成は以下のようにするのが推奨です。
プロジェクトルート
- アプリケーション本体のプロジェクト(例:
YourApp
)とテストプロジェクト(例:YourApp.Tests
)を同じソリューションファイル内に置きます。
- アプリケーション本体のプロジェクト(例:
ディレクトリ構成
- YourSolution.sln
├── YourApp/
│ ├── Controllers/
│ ├── Services/
│ └── Models/
└── YourApp.Tests/
├── Controllers/
├── Services/
└── Models/
テストプロジェクト(YourApp.Tests
)はアプリケーションの構造を反映させ、テスト対象と同じ名前のディレクトリを作成します。たとえば、Controllers
ディレクトリ内にコントローラテストを配置し、ファイル名もコントローラ名に合わせると管理が容易です。
例: テストクラス名と配置
YourApp.Controllers.SampleController.cs
に対して、テストプロジェクトにはYourApp.Tests.Controllers.SampleControllerTests.cs
のように配置します。
推奨する構成
- 各テストクラスでは
Fact
やTheory
を使って異なるテストケースを記述します。 Arrange-Act-Assert
パターンに従うと、コードの意図が明確になり、メンテナンスが容易です。
- 各テストクラスでは
ということなので、基本はテスト対象と同じディレクトリ構成にして、[テスト対象のファイル名]Tests.cs
という名前でファイルを作成していくのがよさそうか。
テスト対象の確認
テスト対象のHomeController.cs
を見ておこう。
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using WebApplication2.Models;
namespace WebApplication2.Controllers
{
using Json.Net;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
このコントローラーをテストするために、ユニットテストを作成していく。
HomeControllerTests.csの作成
- WebAPplication2.sln
└── WebApplication2.Tests
└── Controllers/HomeControllerTests.cs
というパスで作成をした。
中身は以下となる。
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using System.Diagnostics;
using WebApplication2.Controllers;
using WebApplication2.Models;
using Xunit;
namespace WebApplication2.Tests.Controllers
{
public class HomeControllerTests
{
private readonly Mock<ILogger<HomeController>> _mockLogger;
private readonly HomeController _controller;
public HomeControllerTests()
{
// Arrange: ILogger<HomeController>をモック
_mockLogger = new Mock<ILogger<HomeController>>();
_controller = new HomeController(_mockLogger.Object);
// HttpContextのモックを作成し、RequestIdを設定
var httpContext = new DefaultHttpContext();
httpContext.TraceIdentifier = "TestRequestId";
// ControllerContextを設定してHttpContextを注入
_controller.ControllerContext = new ControllerContext
{
HttpContext = httpContext
};
}
[Fact]
public void Index_ReturnsViewResult()
{
// Act
var result = _controller.Index();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
Assert.NotNull(viewResult);
}
[Fact]
public void Privacy_ReturnsViewResult()
{
// Act
var result = _controller.Privacy();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
Assert.NotNull(viewResult);
}
[Fact]
public void Error_ReturnsViewResultWithErrorViewModel()
{
// Act
var result = _controller.Error();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsType<ErrorViewModel>(viewResult.Model);
Assert.Equal("TestRequestId", model.RequestId);
}
}
}
テストの実行
テストも作成できたので、実行をしてみる。
1. 「WebApplication2.Tests(テストプロジェクト)」を右クリック、「テストの実行」を選択する
2. 実行が完了すると結果が表示される
これで、テストは完了できたので終了!
参考
ASP.NET Core サービスと Web アプリのテスト
https://learn.microsoft.com/ja-jp/dotnet/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps.NET でのテスト https://learn.microsoft.com/ja-jp/dotnet/core/testing/
dotnet テストと xUnit を使用した .NET での単体テスト C#
https://learn.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-with-dotnet-test.NET Core と .NET Standard での単体テストのベスト プラクティス
https://learn.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-best-practices
おわりに
xUnit
を使ってユニットテストの作成を行った。
AIがでてからテストケースの生成はかなりし易くなったと感じるので、ちゃんとテストを書いていきたい。
次回以降は、vue
, vite
, TypeScript
をフロントエンドに入れてみたいなあと思う。
このあたりができたら、vitest
でのフロントエンドテストを入れて、最後に ASP.NET Core
のアプリをAzure
にデプロイするということをやりたい。
あとは、swagger
でのAPIのMockや、VSCode
のThunderClient
でAPIのリクエスト投げるとかの記事も書いておきたい。