このチュートリアルでは、単体テストの概念を学習するためのサンプル ソリューションを段階的に構築する対話型エクスペリエンスについて説明します。
この記事では、.NET Core プロジェクトのテストについて説明します。 もし ASP.NET Core プロジェクトをテストする場合は、ASP.NET Core の統合テストを参照してください。
Prerequisites
- .NET 10 SDK 以降のバージョン。
- 任意のテキスト エディターまたはコード エディター。
TUnit は完全に Microsoft.Testing.Platform (MTP) 上に構築されており、VSTest はサポートしていません。 このチュートリアルでは、dotnet testの MTP モードを使用します。これには、.NET 10 SDK が必要です。
ソース プロジェクトを作成する
シェル ウィンドウを開きます。 ソリューションを保持するために 、unit-testing-with-fsharp という名前のディレクトリを作成します。 この新しいディレクトリ内で、次のコマンドを実行して、クラス ライブラリとテスト プロジェクト用の新しいソリューション ファイルを作成します。
dotnet new sln
次に、 MathService ディレクトリを作成します。 次のアウトラインは、これまでのディレクトリとファイルの構造を示しています。
/unit-testing-with-fsharp
unit-testing-with-fsharp.slnx
/MathService
MathService を現在のディレクトリにし、次のコマンドを実行してソース プロジェクトを作成します。
dotnet new classlib -lang "F#"
Library.fs の内容を、数学サービスの失敗する実装に置き換えます。
namespace MathService
module MyMath =
let squaresOfOdds (xs: int seq) : int seq = raise (System.NotImplementedException("You haven't written a test yet!"))
ディレクトリを unit-testing-with-fsharp ディレクトリに戻します。 次のコマンドを実行して、クラス ライブラリ プロジェクトをソリューションに追加します。
dotnet sln add ./MathService/MathService.fsproj
テスト プロジェクトを作成する
次に、 MathService.Tests ディレクトリを作成します。 次のアウトラインは、ディレクトリ構造を示しています。
/unit-testing-with-fsharp
unit-testing-with-fsharp.slnx
/MathService
Source Files
MathService.fsproj
/MathService.Tests
TUnit プロジェクト テンプレートは、.NET SDK には含まれません。 次のコマンドを使用してインストールします。
dotnet new install TUnit.Templates
MathService.Tests ディレクトリを現在のディレクトリにし、次のコマンドを使用して新しいプロジェクトを作成します。
dotnet new TUnit -lang "F#"
Note
テンプレートの短縮名では、大文字と小文字が区別されます。
TUnit ではなく、tunit を使用してください。
このコマンドは、TUnit をテスト フレームワークとして使用するテスト プロジェクトを作成します。 生成された MathService.Tests.fsproj ファイルは、テスト フレームワーク、アサーション ライブラリ、MTP テスト ランナーが含まれる TUnit パッケージと、アサーション用の F# ヘルパーを追加する TUnit.Assertions.FSharp パッケージを参照する実行可能プロジェクトです。
このテンプレートでは、サンプル テストも追加されます。 このチュートリアルでは、それらを Tests.fs 内の独自のテストに置き換えます。
Data ディレクトリと GlobalSetup.fs、Tests2.fs、Tests3.fs ファイルを削除してください。 F# プロジェクトではソース ファイルが明示的に一覧表示されるため、MathService.Tests.fsproj 内の Compile 項目を含む ItemGroup も次に置き換えます。
<ItemGroup>
<Compile Include="Tests.fs" />
</ItemGroup>
次に、 MathService クラス ライブラリを別の依存関係としてプロジェクトに追加します。
dotnet reference add コマンドを使用する。
dotnet reference add ../MathService/MathService.fsproj
次のアウトラインは、最終的なソリューション レイアウトを示しています。
/unit-testing-with-fsharp
unit-testing-with-fsharp.slnx
/MathService
Source Files
MathService.fsproj
/MathService.Tests
Test Source Files
MathService.Tests.fsproj
unit-testing-with-fsharp ディレクトリで次のコマンドを実行します。
dotnet sln add ./MathService.Tests/MathService.Tests.fsproj
dotnet テストの MTP モードを構成する
TUnit は VSTest をサポートしていないため、 dotnet test は MTP モードで実行する必要があります。
unit-testing-with-fsharp ディレクトリで、次の内容を含む global.json ファイルを作成します。
{
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
詳細については、 dotnet テストの MTP モードを参照してください。
最初のテストを作成する
失敗したテストを 1 つ記述し、合格させ、プロセスを繰り返します。 Tests.fs の内容を次のコードに置き換えてください。
namespace MathService.Tests
open TUnit.Core
open TUnit.Assertions
open TUnit.Assertions.Extensions
open TUnit.Assertions.FSharp.TaskAssert
open MathService
type TestClass () =
[<Test>]
member this.TestMethodPassing() = taskAssert {
do! Assert.That(true).IsTrue()
}
[<Test>]
member this.FailEveryTime() = taskAssert {
do! Assert.That(false).IsTrue()
}
[<Test>]属性は、テスト ランナーによって実行されるテスト メソッドを表します。 TUnit は、クラスのメンバーであるテスト メソッドを検出します。モジュール内の let で宣言されている関数は検出されません。 TUnit アサーションは非同期です。
TUnit.Assertions.FSharp の taskAssert 評価式は、タスクとしてテストを実行するため、do! を使用して各アサーションを待機できます。
unit-testing-with-fsharp ディレクトリから、dotnet testを実行してテストとクラス ライブラリをビルドし、テストを実行します。 TUnit テスト プロジェクトには、テストを実行するためのプログラム エントリ ポイントが含まれています。
dotnet test は、作成した単体テスト プロジェクトを使用してテスト アプリケーションを起動します。
これら 2 つのテストは、最も基本的な合格テストと失敗したテストを示しています。
TestMethodPassing が渡され、 FailEveryTime が失敗します。 次に、 squaresOfOdds メソッドのテストを作成します。
squaresOfOdds メソッドは、入力シーケンスの一部であるすべての奇数整数値の 2 乗のシーケンスを返します。 これらの関数をすべて一度に記述するのではなく、機能を検証するテストを繰り返し作成できます。 各テストを成功させるために、メソッドに必要な機能を作成します。
記述できる最も簡単なテストは、すべての偶数で squaresOfOdds を呼び出す方法です。結果は空の整数シーケンスである必要があります。
TestClass型に次のテストを追加します。
[<Test>]
member this.TestEvenSequence() = taskAssert {
let expected = Seq.empty<int>
let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
do! Assert.That<int>(actual).IsEquivalentTo(expected)
}
F# はメソッドのオーバーロードを解決するときに C# よりも厳密であるため、テストは項目の型を Assert.That<int> に渡して、整数のシーケンスのアサーションを選択します。
IsEquivalentTo は、両方のシーケンスに同じ項目が含まれていることを確認します。
テストを実行すると、テストが失敗することがわかります。 これは、実装をまだ作成していないためです。 MathService プロジェクトの Library.fs ファイルに動作する最も単純なコードを記述して、このテストを成功させる。
let squaresOfOdds xs =
Seq.empty<int>
unit-testing-with-fsharp ディレクトリで、dotnet testをもう一度実行します。
dotnet test コマンドは、MathService プロジェクトのビルドを実行してから、MathService.Tests プロジェクトに対してビルドを実行します。 両方のプロジェクトをビルドすると、テストが実行されます。 2 つのテストが合格しました。
要件を満たす
テストが1つ成功したので、さらに多くのテストケースを書きましょう。 次の単純なケースは、唯一の奇数が1であるシーケンスで動作します。 1 の 2 乗は 1 であるため、数値 1 の方が簡単です。 次のテストを次に示します。
[<Test>]
member public this.TestOnesAndEvens() = taskAssert {
let expected = [1; 1; 1; 1]
let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
do! Assert.That<int>(actual).IsEquivalentTo(expected)
}
dotnet testを実行すると、新しいテストが失敗します。 この新しいテストを処理するには、 squaresOfOdds メソッドを更新する必要があります。 このテストを成功させるには、シーケンスからすべての偶数をフィルター処理する必要があります。 これを行うには、小さなフィルター関数を記述し、 Seq.filterを使用します。
let private isOdd x = x % 2 <> 0
let squaresOfOdds xs =
xs
|> Seq.filter isOdd
残りのステップは、すべての奇数をそれぞれ2乗することです。 まず、新しいテストを記述します。
[<Test>]
member public this.TestSquaresOfOdds() = taskAssert {
let expected = [1; 9; 25; 49; 81]
let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
do! Assert.That<int>(actual).IsEquivalentTo(expected)
}
テストを修正するには、フィルター処理されたシーケンスをマップ操作でパイプ処理し、各奇数の 2 乗を計算します。
let private square x = x * x
let private isOdd x = x % 2 <> 0
let squaresOfOdds xs =
xs
|> Seq.filter isOdd
|> Seq.map square
あなたは、小さなライブラリとそのライブラリの単体テストのセットを構築しました。 新しいパッケージとテストの追加が通常のワークフローの一部になるように、ソリューションを構造化しました。 アプリケーションの目標を解決するために、ほとんどの時間と労力を集中しました。
参照
- TUnit のドキュメント
- TUnit の F# アサーション
- dotnet new
- dotnet sln
- dotnet reference add コマンドを使用して参照を追加します。
- dotnet test
.NET