次の方法で共有


dotnet テストと xUnit を使用した .NET Core での F# ライブラリの単体テスト

このチュートリアルでは、単体テストの概念を学習するためのサンプル ソリューションを段階的に構築する対話型エクスペリエンスについて説明します。 事前に構築されたソリューションを使ってチュートリアルを進めたい場合は、開始する前にサンプルコードを表示またはダウンロードしてください。 ダウンロード手順については、サンプルとチュートリアルを参照してください。

この記事では、.NET Core プロジェクトのテストについて説明します。 もし ASP.NET Core プロジェクトをテストする場合は、ASP.NET Core の統合テストを参照してください。

ソース プロジェクトの作成

シェル ウィンドウを開きます。 ソリューションを保持するために 、unit-testing-with-fsharp という名前のディレクトリを作成します。 この新しいディレクトリ内で、 dotnet new sln を実行して新しいソリューションを作成します。 これにより、クラス ライブラリと単体テスト プロジェクトの両方を簡単に管理できます。 ソリューション ディレクトリ内に MathService ディレクトリを作成します。 ここまでのディレクトリとファイルの構造を次に示します。

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService

MathService を現在のディレクトリにし、dotnet new classlib -lang "F#"実行してソース プロジェクトを作成します。 数学サービスの失敗した実装を作成します。

module MyMath =
    let squaresOfOdds xs = 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.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests

MathService.Tests ディレクトリを現在のディレクトリにし、dotnet new xunit -lang "F#"を使用して新しいプロジェクトを作成します。 これにより、xUnit をテスト ライブラリとして使用するテスト プロジェクトが作成されます。 生成されたテンプレートは、 MathServiceTests.fsproj でテスト ランナーを構成します。

<ItemGroup>
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
  <PackageReference Include="xunit" Version="2.2.0" />
  <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>

テスト プロジェクトでは、単体テストを作成して実行するために他のパッケージが必要です。 dotnet new 前の手順で xUnit と xUnit ランナーを追加しました。 次に、 MathService クラス ライブラリを別の依存関係としてプロジェクトに追加します。 dotnet reference add コマンドを使用します。

dotnet reference add ../MathService/MathService.fsproj

ファイル全体は GitHub の サンプル リポジトリ で確認できます。

最終的なソリューション レイアウトは次のとおりです。

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests
        Test Source Files
        MathServiceTests.fsproj

dotnet sln add .\MathService.Tests\MathService.Tests.fsproj ディレクトリでを実行します。

最初のテストの作成

失敗したテストを 1 つ記述し、合格させ、プロセスを繰り返します。 Tests.fs を開き、次のコードを追加します。

[<Fact>]
let ``My test`` () =
    Assert.True(true)

[<Fact>]
let ``Fail every time`` () = Assert.True(false)

[<Fact>]属性は、テスト ランナーによって実行されるテスト メソッドを表します。 unit-testing-with-fsharp から、dotnet testを実行してテストとクラス ライブラリをビルドし、テストを実行します。 xUnit テスト ランナーには、テストを実行するためのプログラム エントリ ポイントが含まれています。 dotnet test を実行すると、作成した単体テスト プロジェクトを使用してテスト ランナーが開始されます。

これら 2 つのテストは、最も基本的な合格テストと失敗したテストを示しています。 My test が渡され、 Fail every time が失敗します。 次に、 squaresOfOdds メソッドのテストを作成します。 squaresOfOdds メソッドは、入力シーケンスの一部であるすべての奇数整数値の 2 乗のシーケンスを返します。 これらの関数をすべて一度に記述するのではなく、機能を検証するテストを繰り返し作成できます。 各テストパスを作成することは、メソッドに必要な機能を作成することを意味します。

私たちが書くことができる最も簡単なテストは、すべての偶数で squaresOfOdds を呼び出す方法です。結果は空の整数シーケンスである必要があります。 そのテストを次に示します。

[<Fact>]
let ``Sequence of Evens returns empty collection`` () =
    let expected = Seq.empty<int>
    let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
    Assert.Equal<Collections.Generic.IEnumerable<int>>(expected, actual)

テストが失敗します。 実装はまだ作成していません。 動作する MathService クラスで最も単純なコードを記述して、このテストを成功させる。

let squaresOfOdds xs =
    Seq.empty<int>

unit-testing-with-fsharp ディレクトリでdotnet testをもう一度実行します。 dotnet test コマンドは、MathService プロジェクトのビルドを実行してから、MathService.Tests プロジェクトに対してビルドを実行します。 両方のプロジェクトをビルドした後、この 1 つのテストを実行します。 成功します。

要件を満たすこと

テストが1つ成功したので、さらに多くのテストケースを書きましょう。 次の単純なケースは、1が唯一の奇数であるシーケンスを使います。 1 の 2 乗は 1 であるため、数値 1 の方が簡単です。 次のテストを次に示します。

[<Fact>]
let ``Sequences of Ones and Evens returns Ones`` () =
    let expected = [1; 1; 1; 1]
    let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
    Assert.Equal<Collections.Generic.IEnumerable<int>>(expected, actual)

dotnet testを実行すると、テストが実行され、新しいテストが失敗することを示します。 次に、 squaresOfOdds メソッドを更新して、この新しいテストを処理します。 このテストを成功させるために、シーケンスからすべての偶数をフィルター処理します。 これを行うには、小さなフィルター関数を記述し、 Seq.filterを使用します。

let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd

残りのステップは、すべての奇数をそれぞれ2乗することです。 まず、新しいテストを記述します。

[<Fact>]
let ``SquaresOfOdds works`` () =
    let expected = [1; 9; 25; 49; 81]
    let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
    Assert.Equal(expected, actual)

テストを修正するには、フィルター処理されたシーケンスをマップ操作でパイプ処理し、各奇数の 2 乗を計算します。

let private square x = x * x
let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd
    |> Seq.map square

あなたは、小さなライブラリとそのライブラリの単体テストのセットを構築しました。 新しいパッケージとテストの追加が通常のワークフローの一部になるように、ソリューションを構築しました。 アプリケーションの目標を解決するために、ほとんどの時間と労力が集中しています。

こちらもご覧ください