跳至頁尾內容
.NET 幫助

Moq C#(開發者使用指南)

在軟體開發的世界裡,測試是一個不可或缺的過程。 它可確保您的程式碼能如預期般運作,並有助於在進入生產階段前捕捉錯誤。 測試的一個重要方面就是模擬,而在 C# 測試方面,MOQ 是開發人員的利器。 它提供對 lambda 表達式的支援。 MOQ 是"Mock Object Framework for .NET"的縮寫,簡化了為單元測試建立模擬物件的過程。 在本文中,我們將深入探討 C# 中的 MOQ。

什麼是 MOQ?

MOQ - Mocking Framework for .NET 是適用於 .NET 應用程式的模擬框架,可讓開發人員快速、有效率地建立模擬物件。 Mock 物件模擬應用程式中真實物件的行為,讓您更容易隔離和測試程式碼的特定部分。 MOQ 簡化了建立和使用這些模擬物件的過程。

MOQ 的主要功能

  • 流暢的介面: MOQ 提供流暢且具表達力的 API,用於設定預期和驗證。 這可讓您的測試程式碼更具可讀性,也更容易理解。
  • Strong Typing: MOQ 利用 C# 語言的特性,在定義模擬和期望時提供強大的類型和 IntelliSense 支援。 這樣可以減少測試中出現執行時錯誤的機會。
  • Loose Mocking: MOQ 支援嚴格和寬鬆的模擬。 Loose mocking 允許您建立回應任何方法呼叫的 mock 物件,而 strict mocking 則強制只呼叫預期的方法。
  • 可驗證的行為: MOQ 可讓您驗證您的模擬物件上的特定方法是否以預期的參數和正確的順序被呼叫。
  • 回調和返回值:您可以定義回調以在呼叫模擬方法時執行自訂程式碼,並指定模擬方法的返回值。

開始使用 MOQ

在本教程中,我們將探討如何使用 MOQ(一個流行的 C# 模擬框架)來促進單元測試。 我們將透過一個範例,使用 MOQ 來模擬依賴關係,建立並測試一個簡單的 ATM 交易情境。

建立新的 C# 專案

請依照下列步驟建立新專案:

1.開啟 Visual Studio,前往"檔案">"新增">"專案..."。 2.選擇專案範本、設定設定,然後按一下"建立"。

Moq C# (How It Works For Developers) 圖 1 - 在 Visual Studio 2022 中建立新的控制台應用程式

假設您正在為 ATM(自動櫃員機)開發軟體,並且需要測試驗證和提款功能。 ATM 取決於兩個介面:IHostBankIHSMModule。 我們想要測試 ATMCashWithdrawal 類,該類代表 ATM 的提款功能。

建立兩個介面,IHostBankIHSMModule 代表 ATM 系統的依賴關係。 定義相關的方法,例如 AuthenticateAmountValidatePIN

// IHostBank.cs
public interface IHostBank
{
    bool AuthenticateAmount(string accountNumber, int amount);
}

// IHSMModule.cs
public interface IHSMModule
{
    bool ValidatePIN(string cardNumber, int pin);
}
// IHostBank.cs
public interface IHostBank
{
    bool AuthenticateAmount(string accountNumber, int amount);
}

// IHSMModule.cs
public interface IHSMModule
{
    bool ValidatePIN(string cardNumber, int pin);
}
$vbLabelText   $csharpLabel

建立ATMCashWithdrawal類別,使用上述的依存關係來執行 ATM 作業。 在這堂課中,您要實作某個方法,例如 WithdrawAmount

// ATMCashWithdrawal.cs
public class ATMCashWithdrawal
{
    private readonly IHSMModule hsmModule;
    private readonly IHostBank hostBank;

    public ATMCashWithdrawal(IHSMModule hsmModule, IHostBank hostBank)
    {
        this.hsmModule = hsmModule;
        this.hostBank = hostBank;
    }

    // Withdraw amount after validating PIN and balance
    public bool WithdrawAmount(string cardNumber, int pin, int amount)
    {
        if (!hsmModule.ValidatePIN(cardNumber, pin))
        {
            return false;
        }

        if (!hostBank.AuthenticateAmount(cardNumber, amount))
        {
            return false;
        }

        // Withdraw the specified amount and perform other operations
        return true;
    }
}
// ATMCashWithdrawal.cs
public class ATMCashWithdrawal
{
    private readonly IHSMModule hsmModule;
    private readonly IHostBank hostBank;

    public ATMCashWithdrawal(IHSMModule hsmModule, IHostBank hostBank)
    {
        this.hsmModule = hsmModule;
        this.hostBank = hostBank;
    }

    // Withdraw amount after validating PIN and balance
    public bool WithdrawAmount(string cardNumber, int pin, int amount)
    {
        if (!hsmModule.ValidatePIN(cardNumber, pin))
        {
            return false;
        }

        if (!hostBank.AuthenticateAmount(cardNumber, amount))
        {
            return false;
        }

        // Withdraw the specified amount and perform other operations
        return true;
    }
}
$vbLabelText   $csharpLabel

建立單元測試專案

現在,讓我們使用 MOQ 來模擬相依性,為 ATMCashWithdrawal 類建立單元測試。

在您的解決方案中建立新的單元測試專案,並將其命名為 ATMSystem.Tests

若要在 Visual Studio 解決方案中加入 NUnit 測試專案,請遵循下列步驟:

1.在解決方案上按一下滑鼠右鍵:在解決方案總管中(通常在右側),按一下解決方案名稱的滑鼠右鍵。 2.新增 > 新專案: 從上下文功能表中選擇"新增",然後選取"新專案..."。 3.建立新專案:在"新增專案"對話方塊中,您可以搜尋"NUnit"以尋找可用的 NUnit 模版。 選擇 NUnit 測試專案,如下所示。

Moq C# (How It Works For Developers) 圖 2 - 在您的解決方案中新增一個 NUnit 測試專案.

4.設定專案:依需要設定專案設定,包括專案名稱和位置。 5.按一下確定:按一下"建立"或"確定"按鈕,將 NUnit 測試專案新增至您的解決方案。

現在,您的解決方案中已有一個獨立的 NUnit 測試專案,您可以在其中編寫和管理您的單元測試。 您也可以在此專案中加入您想要測試的專案參考,並開始撰寫您的 NUnit 測試案例。

若要開始在測試專案中使用 MOQ,您需要將 MOQ NuGet 套件新增至您的解決方案中。 您可以使用 Visual Studio 中的 NuGet Package Manager 或在 Package Manager Console 中執行以下指令來完成:

Install-Package Moq

此指令將安裝套件,並將所有所需的相依性加入專案中。

使用 NUnit 和 MOQ 撰寫單元測試,以模擬 ATMCashWithdrawal class 的依賴項目 (IHostBankIHSMModule) 。

using Moq;
using NUnit.Framework;

namespace ATMSystem.Tests
{
    public class ATMTests
    {
        private ATMCashWithdrawal atmCash;

        [SetUp]
        public void Setup()
        {
            // Arrange - Setup mock objects
            var hsmModuleMock = new Mock<IHSMModule>();
            hsmModuleMock.Setup(h => h.ValidatePIN("123456781234", 1234)).Returns(true);

            var hostBankMock = new Mock<IHostBank>();
            hostBankMock.Setup(h => h.AuthenticateAmount("123456781234", 500)).Returns(true);

            atmCash = new ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object);
        }

        [Test]
        public void WithdrawAmount_ValidTransaction_ReturnsTrue()
        {
            // Act - Execute the method under test
            bool result = atmCash.WithdrawAmount("123456781234", 1234, 500);

            // Assert - Verify the result
            Assert.IsTrue(result);
        }

        // More test cases for different scenarios (e.g., invalid PIN, insufficient funds)
    }
}
using Moq;
using NUnit.Framework;

namespace ATMSystem.Tests
{
    public class ATMTests
    {
        private ATMCashWithdrawal atmCash;

        [SetUp]
        public void Setup()
        {
            // Arrange - Setup mock objects
            var hsmModuleMock = new Mock<IHSMModule>();
            hsmModuleMock.Setup(h => h.ValidatePIN("123456781234", 1234)).Returns(true);

            var hostBankMock = new Mock<IHostBank>();
            hostBankMock.Setup(h => h.AuthenticateAmount("123456781234", 500)).Returns(true);

            atmCash = new ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object);
        }

        [Test]
        public void WithdrawAmount_ValidTransaction_ReturnsTrue()
        {
            // Act - Execute the method under test
            bool result = atmCash.WithdrawAmount("123456781234", 1234, 500);

            // Assert - Verify the result
            Assert.IsTrue(result);
        }

        // More test cases for different scenarios (e.g., invalid PIN, insufficient funds)
    }
}
$vbLabelText   $csharpLabel

在此測試代碼中,我們使用 MOQ 為 IHSMModuleIHostBank 建立模擬物件,並指定它們在測試期間被呼叫時的行為。

在上面的程式碼範例中,我們已經在 C# 中展示了使用 MOQ 模擬物件的概念。 我們為 IHSMModuleIHostBank 介面建立模擬物件,在單元測試時模擬它們的行為。 這可讓我們透過控制這些模擬物件的回應,隔離並徹底測試 ATMCashWithdrawal 類別。 透過 mocking,我們可以確保程式碼能正確地與這些相依性互動,讓我們的測試更有焦點、更可預測,並能有效找出所檢查的特定程式碼單元中的問題。 此做法可提升整體可靠性、可維護性及測試代碼的品質。

步驟 3 執行測試

1.建立您的解決方案,確保所有內容都是最新的。 2.開啟 Visual Studio 中的 Test Explorer (Test > Test Explorer)。 3.按一下 Test Explorer 中的"Run All"按鈕來執行單元測試。 4.檢閱測試結果。 您應該會看到您所寫的測試 (WithdrawAmount_ValidTransaction_ReturnsTrue) 通過。

Moq C# (How It Works For Developers) 圖 3 - 要執行 Tests,首先要建立解決方案。 成功建置後,開啟 Visual Studio 中的測試總覽器,點選執行全部按鈕,即可開始執行單元測試。

透過這種方式,我們可以隔離想要測試的程式碼,並透過有效的模擬依賴關係,確保程式碼在各種情況下的行為符合預期。 這種做法可提高軟體的可靠性和可維護性,讓您更容易在開發過程中及早發現並修復問題。

介紹 IronPDF。

IronPDF 文件和功能概述是一個功能強大的 C# 函式庫,可讓開發人員在其應用程式中處理 PDF 文件。 它提供廣泛的功能,包括從 HTML、影像和現有 PDF 等各種來源建立、修改和轉換 PDF 檔案。 如果結合之前教學中所討論的模擬物件概念,IronPDF 將成為您在單元測試中產生與操作 PDF 文件的重要工具。

IronPDF 的主要功能是其 HTML 到 PDF 的轉換功能,可確保版面設計和樣式完好無損。 它可將網頁內容轉換成 PDF,非常適合報告、發票和文件。 此功能支援將 HTML 檔案、URL 和 HTML 字串轉換為 PDF。

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
$vbLabelText   $csharpLabel

例如,如果您有涉及 PDF 生成或处理的项目,您可以使用 IronPDF 创建模仿真实场景的模拟 PDF 文档。 這對於測試和驗證您的程式碼如何與 PDF 檔案互動特別有用。 您可以生成具有特定內容、佈局和屬性的模擬 PDF,然後將它們用作測試夾具,以確保您的程式碼能產生所需的 PDF 輸出或正確處理 PDF 相關作業。

建立模擬物件以產生 PDFs

假設您正在開發一個會產生財務報告的應用程式,而這些報告需要以 PDF 文件的形式儲存與散佈。 在這種情況下,您可能想要測試 PDF 的產生,並確保內容和格式正確無誤。

首先,我們需要在專案中加入 IronPdf。 在 NuGet Package Manager Console 中編寫以下指令以安裝 IronPDF。

Install-Package IronPdf

此指令將安裝及新增必要的相依性至我們的專案。

以下是 IronPdf 如何融入單元測試流程:

產生模擬 PDFs

您可以使用 IronPDF 創建具有特定內容和樣式的模擬 PDF 文件,以模仿真實的財務報告。 這些模擬 PDF 可以作為您單元測試的測試夾具,如以下程式碼片段所示:

public class PDFGenerator
{
    public void GenerateFinancialReport(string reportData)
    {
        var renderer = new ChromePdfRenderer();

        // Generate the report HTML
        string reportHtml = GenerateReportHtml(reportData);
        PdfDocument pdfDocument = renderer.RenderHtmlAsPdf(reportHtml);

        // Save the PDF to a file or memory stream
        pdfDocument.SaveAs("FinancialReport.pdf");
    }

    private string GenerateReportHtml(string reportData)
    {
        // Generate the report HTML based on the provided data
        // (e.g., using Razor views or any HTML templating mechanism)
        // Return the HTML as a string
        return "<h1>my Report</h1>";
    }
}
public class PDFGenerator
{
    public void GenerateFinancialReport(string reportData)
    {
        var renderer = new ChromePdfRenderer();

        // Generate the report HTML
        string reportHtml = GenerateReportHtml(reportData);
        PdfDocument pdfDocument = renderer.RenderHtmlAsPdf(reportHtml);

        // Save the PDF to a file or memory stream
        pdfDocument.SaveAs("FinancialReport.pdf");
    }

    private string GenerateReportHtml(string reportData)
    {
        // Generate the report HTML based on the provided data
        // (e.g., using Razor views or any HTML templating mechanism)
        // Return the HTML as a string
        return "<h1>my Report</h1>";
    }
}
$vbLabelText   $csharpLabel

使用模擬 PDF 進行單元測試

我們將為使用 IronPDF 來產生代表各種報告情境的模擬 PDF 寫測試。 然後,我們會將程式碼產生的實際 PDF 與這些模擬 PDF 進行比較,以確保內容、格式和結構符合預期。

using IronPdf;
using NUnit.Framework;

internal class PDFGeneratorTests
{
    [Test]
    public void GenerateFinancialReport_CreatesCorrectPDF()
    {
        // Arrange
        var pdfGenerator = new PDFGenerator();
        var expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf"); // Load a mock PDF

        // Act
        pdfGenerator.GenerateFinancialReport("Sample report data");
        var actualPdf = PdfDocument.FromFile("FinancialReport.pdf");

        // Assert
        Assert.AreEqual(actualPdf.ExtractAllText(), expectedPdf.ExtractAllText());
    }
}
using IronPdf;
using NUnit.Framework;

internal class PDFGeneratorTests
{
    [Test]
    public void GenerateFinancialReport_CreatesCorrectPDF()
    {
        // Arrange
        var pdfGenerator = new PDFGenerator();
        var expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf"); // Load a mock PDF

        // Act
        pdfGenerator.GenerateFinancialReport("Sample report data");
        var actualPdf = PdfDocument.FromFile("FinancialReport.pdf");

        // Assert
        Assert.AreEqual(actualPdf.ExtractAllText(), expectedPdf.ExtractAllText());
    }
}
$vbLabelText   $csharpLabel

在此測試程式碼中,我們會產生代表預期輸出的模擬 PDF (expectedPdf),並與 PDFGenerator 所產生的 PDF (actualPdf) 進行比較。 我們提取了兩份 PDF 的內容,以驗證它們是否具有相同的內容。

結論

總而言之,在單元測試流程中利用 MOQ 與 IronPDF,可讓我們全面驗證軟體應用程式的行為。 MOQ 讓我們能夠隔離特定的程式碼元件、控制相依性,並模擬複雜的情境,讓我們能夠撰寫重點且可靠的測試。

與此同時,IronPdf 透過促進 PDF 文件的產生和操作,增強了我們的測試能力,確保我們的 PDF 相關功能得到徹底檢驗。 將這些工具整合到我們的測試工具包中,我們就能有信心開發出強大且高品質的軟體,滿足功能與效能的需求。 使用 MOQ 進行強大的單元測試,並使用 IronPDF 進行 PDF 驗證,這種組合對我們應用程式的整體品質和可靠性貢獻良多。

值得注意的是,IronPDF 提供免費試用以測試其功能。 如果您發現它符合您的需求,您可以選擇購買 商業授權,它允許您在您的專案中繼續使用 IronPdf 的功能,並享有授權版本所帶來的完整優勢和支援,確保 PDF 相關功能順利整合到您的應用程式中。

常見問題解答

Moq 如何增強 C# 中的單元測試?

Moq 透過讓開發人員建立模擬物件來模擬真實物件的行為,從而增強了 C# 中的單元測試。這有助於隔離開發人員希望測試的特定程式碼元件,從而確保更準確、更有針對性的測試結果。

Moq的主要特點是什麼?

Moq 提供了一個流暢的介面來設定預期,強型別來減少執行階段錯誤,並且支援嚴格且寬鬆的模擬,使其成為 C# 應用程式單元測試的有效工具。

如何將 IronPDF 整合到 C# 專案中以產生 PDF 文件?

若要將 IronPDF 整合到 C# 專案中,可以使用 NuGet 套件管理器控制台並執行命令Install-Package IronPdf 。這將會新增在應用程式中產生和操作 PDF 所需的依賴項。

在單元測試中使用模擬 PDF 的目的是什麼?

單元測試中使用模擬 PDF 檔案來模擬涉及 PDF 文件的真實場景。這使得開發人員能夠測試 PDF 的生成和操作功能,確保他們的應用程式能夠正確處理 PDF 文件。

IronPDF 可以用於商業應用嗎?

是的,IronPDF 提供商業許可選項,允許開發人員在商業應用程式中使用其全部 PDF 功能,並獲得許可版本提供的支援和功能。

如何在單元測試中同時使用 Moq 和 IronPDF?

Moq 可用於模擬程式碼中的依賴項,而 IronPDF 可用於產生和操作 PDF 檔案。它們結合使用,使開發人員能夠編寫可靠的測試,從而確保程式碼邏輯和 PDF 相關功能的品質。

在 C# 中測試依賴關係互動時,Moq 扮演什麼角色?

Moq 透過允許開發人員建立介面(例如 `IHostBank` 和 `IHSMModule`)的模擬實現,幫助測試依賴項互動。這使您可以模擬各種場景,並驗證您的程式碼是否按預期與依賴項互動。

Moq 如何處理嚴格和寬鬆的模擬?

Moq 同時支援嚴格模擬和寬鬆模擬。嚴格模擬要求所有預期都必須滿足,這對於精確測試非常有用。寬鬆模擬則更加靈活,允許僅驗證感興趣的交互,這在複雜系統中尤其重要。

Jacob Mellor,Team Iron 首席技術官
首席技術長

Jacob Mellor 是 Iron Software 的首席技術官,也是一位富有遠見的工程師,率先開發了 C# PDF 技術。作為 Iron Software 核心程式碼庫的最初開發者,他自公司成立之初便參與塑造了其產品架構,並與執行長 Cameron Rimington 一起將其發展成為一家擁有 50 多名員工、服務於 NASA、特斯拉和全球政府機構的公司。

Jacob 於 1998 年至 2001 年在曼徹斯特大學獲得土木工程一級榮譽學士學位。 1999 年,他在倫敦創辦了自己的第一家軟體公司;2005 年,他創建了自己的第一個 .NET 元件。此後,他專注於解決微軟生態系統中的複雜問題。

他的旗艦產品 IronPDF 和 IronSuite .NET 庫在全球 NuGet 上的安裝量已超過 3000 萬次,其基礎程式碼持續為全球開發者工具提供支援。憑藉 25 年的商業經驗和 41 年的程式設計專長,Jacob 始終致力於推動企業級 C#、Java 和 Python PDF 技術的創新,同時指導下一代技術領導者。