共用方式為


使用 dotnet test 和 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 目錄中執行

建立第一個測試

您撰寫一個失敗的測試,讓它通過,接著重複這個過程。 開啟 Tests.fs,並新增下列程式代碼:

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

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

[<Fact>] 屬性表示測試執行器所執行的測試方法。 從 unit-testing-with-fsharp 執行命令來建置測試和類別庫,然後運行測試。 xUnit 測試執行器包含執行測試的程式進入點。 dotnet test 使用您建立的單元測試專案啟動測試執行器。

這兩個測試顯示了最基本的通過測試和失敗測試的結果。 My test 通過,而 Fail every time 失敗。 現在,為 squaresOfOdds 方法建立測試。 squaresOfOdds 方法會傳回屬於輸入序列之所有奇數整數值的平方的一個序列。 您可以反覆建立驗證功能的測試,而不是一次嘗試撰寫所有這些函式。 使每個測試通過意味著為方法創建必要的功能。

我們可以撰寫的最簡單測試是用所有偶數調用 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 testdotnet test 命令會執行 MathService 項目的組建,然後執行 MathService.Tests 項目的組建。 建置這兩個項目之後,它會執行此單一測試。 它通過了。

完成所有需求

既然您已通過一次測試,現在是時候撰寫更多了。 下一個簡單案例適用於只有奇數 1的序列。 數位 1 比較容易,因為 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

還有一個步驟要走:平方每個奇數。 從撰寫新的測試開始:

[<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)

您可以透過映射函數將篩選後的序列運算,以計算每個奇數的平方來修正測試:

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

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

您已建立一個小型程式庫及其一組單元測試。 您已建構解決方案,以便新增新的套件和測試是一般工作流程的一部分。 您大部分的時間和精力都集中在解決應用程式的目標上。

另請參閱