The Will Will Web | 如何將現有 .NET Core 專案加入相對應的 xUnit 單元測試專案

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何將現有 .NET Core 專案加入相對應的 xUnit 單元測試專案

在 Visual Studio 2017 開發工具裡,建立單元測試專案有好幾種方法,其中一種是將現有專案增加一個相對應的單元測試專案。在傳統 .NET Framework 專案中,很輕易的就可以建立完成,只要在任一類別上按下滑鼠右鍵,選擇「建立單元測試」即可。但在 .NET Core 專案中就沒那麼方便了,因為這個功能一直沒被實現。本篇文章將分享如何依據現有專案的程式碼,產生相對應的單元測試專案,一步一步帶大家了解建立單元測試專案的過程。

從類別庫專案開始

首先,我們先建立一個 .NET Core 的「類別庫」專案 (Class Library),專案名稱假設為 ClassLibrary1,我們的專案中只有一個 MathLib 類別,且程式碼也相當簡單,只有 4 個方法 (Methods)。如下範例:

namespace ClassLibrary1
{
    public class MathLib
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
        public int Sub(int a, int b)
        {
            return a - b;
        }
        public int Mul(int a, int b)
        {
            return a * b;
        }
        public float Div(int a, int b)
        {
            return a / b;
        }
    }
}

加入單元測試專案

由於 Visual Studio 2017 目前還無法針對現有 .NET Core 專案方便的建立單元測試專案,所以步驟會稍微複雜一點。

  1. 我們先在現有方案中,手動建立一個全新的 xUnit 單元測試專案,專案名稱可命名為 ClassLibrary1Test。建立完成後,請先透過 NuGet 套件管理員將 xunit 相關套件升級到最新版本。

  2. 刪除預設的 UnitTest1.cs 檔案。

  3. 調整 ClassLibrary1Test 專案的相依性,將 ClassLibrary1 專案加入參考。

  4. 安裝 Unit Test Boilerplate Generator 擴充套件

    • 請注意:這裡要安裝的不是 NuGet 套件喔!而是 Visual Studio 2017 的擴充套件!
    • 安裝完成後,必須先關閉 Visual Studio 2017,安裝套件,再重開專案才行!
  5. 直接從方案總管選取 MathLib.cs 檔案,並按下滑鼠右鍵,選擇 Create Unit Test Boilerplate,然後在對話框中設定正確的單元測試專案、測試框架,以及想用的 Mock Framework,就可以自動產生測試類別/測試方法。

    請注意:透過工具只會幫你大致寫好要測試的程式骨架(3A Pattern),事實上範例程式幾乎都不能用,還必須修改過才行。

  6. 修正程式碼

    • 先移除 using NSubstitute; (因為目前用不到)
    • 把所有 TODO 全部都改為 2
    • 最後把 Assert.Fail(); 修正為 Assert.True(false); (全部都會測試失敗)

完成後的程式碼如下:

using ClassLibrary1;
using Xunit;

namespace ClassLibrary1Test
{
    public class MathLibTests
    {


        public MathLibTests()
        {

        }


        private MathLib CreateMathLib()
        {
            return new MathLib();
        }

        [Fact]
        public void Add_StateUnderTest_ExpectedBehavior()
        {
            // Arrange
            var unitUnderTest = CreateMathLib();
            int a = 2;
            int b = 2;

            // Act
            var result = unitUnderTest.Add(
                a,
                b);

            // Assert
            Assert.True(false);
        }

        [Fact]
        public void Sub_StateUnderTest_ExpectedBehavior()
        {
            // Arrange
            var unitUnderTest = CreateMathLib();
            int a = 2;
            int b = 2;

            // Act
            var result = unitUnderTest.Sub(
                a,
                b);

            // Assert
            Assert.True(false);
        }

        [Fact]
        public void Mul_StateUnderTest_ExpectedBehavior()
        {
            // Arrange
            var unitUnderTest = CreateMathLib();
            int a = 2;
            int b = 2;

            // Act
            var result = unitUnderTest.Mul(
                a,
                b);

            // Assert
            Assert.True(false);
        }

        [Fact]
        public void Div_StateUnderTest_ExpectedBehavior()
        {
            // Arrange
            var unitUnderTest = CreateMathLib();
            int a = 2;
            int b = 2;

            // Act
            var result = unitUnderTest.Div(
                a,
                b);

            // Assert
            Assert.True(false);
        }
    }
}

執行所有測試

  1. 從主選單找到 [測試] -> [視窗] -> [Test Explorer] 即可開啟測試總管

  2. 從主選單找到 [測試] -> [執行] -> [所有測試] 執行所有測試

如何測試私有類別

撰寫單元測試的時候,我們有時候會需要測試專案中的私有類別。我們先修改 MathLib.cs 類別檔,將 public class MathLib 改為 class MathLib,用來模擬私有類別的情況。

此時進行建置,你就會發現我們的 ClassLibrary1Test 單元測試專案已經無法看見 ClassLibrary1 專案中的 MathLib 類別了!

這個問題在單元測試專案中算是相當常見的,而且有標準的解決方法,那就是使用 InternalsVisibleToAttribute 進行宣告。

以前我們在建立 .NET Framework 專案時,都會有個 Properties\AssemblyInfo.cs 檔案。但是在 .NET Core 中,由於架構改變的關係,原本這個檔案的內容,大多已經搬到 *.csproj 專案檔中,所以這個檔案預設已經不存在了!

但在寫單元測試的時候,你只要把它加回來即可。請修改  ClassLibrary1  專案,加入 Properties\AssemblyInfo.cs 檔案,並設定成以下兩行內容:

using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo(assemblyName: "ClassLibrary1Test")]

請注意:上述程式碼的 ClassLibrary1Test 字串,要設定為單元測試專案的組件名稱!

最後,我們只要再重建一次專案,就會發現單元測試專案已經可以成功建置與執行了!

相關連結