Moq C#(開發者的工作原理)
在軟體開發的世界裡,測試是一個不可或缺的過程。 它可確保您的程式碼能如預期般運作,並有助於在進入生產階段前捕捉錯誤。 測試的一個重要方面就是模擬,而在 C# 測試方面,MOQ 是開發人員的利器。 它提供對 lambda 表達式的支援。 MOQ 是"Mock Object Framework 適用於 .NET"的縮寫,簡化了為單元測試建立模擬物件的過程。 在本文中,我們將深入探討 C# 中的 MOQ。
什麼是 MOQ?
MOQ - Mocking Framework 適用於 .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.選擇專案範本、設定設定,然後按一下"建立"。
。
假設您正在為 ATM(自動櫃員機)開發軟體,並且需要測試驗證和提款功能。 ATM 依賴兩個介面:IHostBank 和 IHSMModule。 我們想要測試 ATMCashWithdrawal 類,該類代表 ATM 的提款功能。
建立兩個接口,IHostBank 和 IHSMModule,它們代表 ATM 系統的依賴關係。 定義相關方法,例如 AuthenticateAmount 和 ValidatePIN。
// 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);
}
' IHostBank.cs
Public Interface IHostBank
Function AuthenticateAmount(ByVal accountNumber As String, ByVal amount As Integer) As Boolean
End Interface
' IHSMModule.cs
Public Interface IHSMModule
Function ValidatePIN(ByVal cardNumber As String, ByVal pin As Integer) As Boolean
End Interface
建立 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;
}
}
' ATMCashWithdrawal.cs
Public Class ATMCashWithdrawal
Private ReadOnly hsmModule As IHSMModule
Private ReadOnly hostBank As IHostBank
Public Sub New(ByVal hsmModule As IHSMModule, ByVal hostBank As IHostBank)
Me.hsmModule = hsmModule
Me.hostBank = hostBank
End Sub
' Withdraw amount after validating PIN and balance
Public Function WithdrawAmount(ByVal cardNumber As String, ByVal pin As Integer, ByVal amount As Integer) As Boolean
If Not hsmModule.ValidatePIN(cardNumber, pin) Then
Return False
End If
If Not hostBank.AuthenticateAmount(cardNumber, amount) Then
Return False
End If
' Withdraw the specified amount and perform other operations
Return True
End Function
End Class
建立單元測試專案
現在,讓我們使用 MOQ 模擬依賴項,為 ATMCashWithdrawal 類別建立單元測試。
在您的解決方案中建立一個新的單元測試項目,並將其命名為 ATMSystem.Tests。
若要在 Visual Studio 解決方案中加入 NUnit 測試專案,請遵循下列步驟:
1.在解決方案上按一下滑鼠右鍵:在解決方案總管中(通常在右側),按一下解決方案名稱的滑鼠右鍵。 2.新增 > 新專案: 從上下文功能表中選擇"新增",然後選取"新專案..."。 3.建立新專案:在"新增專案"對話方塊中,您可以搜尋"NUnit"以尋找可用的 NUnit 模版。 選擇 NUnit 測試專案,如下所示。
。
4.設定專案:依需要設定專案設定,包括專案名稱和位置。 5.按一下確定:按一下"建立"或"確定"按鈕,將 NUnit 測試專案新增至您的解決方案。
現在,您的解決方案中已有一個獨立的 NUnit 測試專案,您可以在其中編寫和管理您的單元測試。 您也可以在此專案中加入您想要測試的專案參考,並開始撰寫您的 NUnit 測試案例。
若要開始在測試專案中使用 MOQ,您需要將 MOQ NuGet 套件新增至您的解決方案中。 您可以使用 Visual Studio 中的 NuGet Package Manager 或在 Package Manager Console 中執行以下指令來完成:
Install-Package Moq
此指令將安裝套件,並將所有所需的相依性加入專案中。
使用 NUnit 和 MOQ 編寫單元測試,模擬 IHostBank 和 IHSMModule 類別的依賴項 (ATMCashWithdrawal)。
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)
}
}
Imports Moq
Imports NUnit.Framework
Namespace ATMSystem.Tests
Public Class ATMTests
Private atmCash As ATMCashWithdrawal
<SetUp>
Public Sub Setup()
' Arrange - Setup mock objects
Dim hsmModuleMock = New Mock(Of IHSMModule)()
hsmModuleMock.Setup(Function(h) h.ValidatePIN("123456781234", 1234)).Returns(True)
Dim hostBankMock = New Mock(Of IHostBank)()
hostBankMock.Setup(Function(h) h.AuthenticateAmount("123456781234", 500)).Returns(True)
atmCash = New ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object)
End Sub
<Test>
Public Sub WithdrawAmount_ValidTransaction_ReturnsTrue()
' Act - Execute the method under test
Dim result As Boolean = atmCash.WithdrawAmount("123456781234", 1234, 500)
' Assert - Verify the result
Assert.IsTrue(result)
End Sub
' More test cases for different scenarios (e.g., invalid PIN, insufficient funds)
End Class
End Namespace
在本測試程式碼中,我們使用 MOQ 為 IHSMModule 和 IHostBank 建立模擬對象,並指定它們在測試期間被呼叫時的行為。
在上面的程式碼範例中,我們已經在 C# 中展示了使用 MOQ 模擬物件的概念。 我們為 IHSMModule 和 IHostBank 介面建立模擬對象,模擬它們在單元測試期間的行為。 這樣,我們就可以透過控制這些模擬物件的反應來隔離並徹底測試 ATMCashWithdrawal 類別。 透過 mocking,我們可以確保程式碼能正確地與這些相依性互動,讓我們的測試更有焦點、更可預測,並能有效找出所檢查的特定程式碼單元中的問題。 此做法可提升整體可靠性、可維護性及測試代碼的品質。
步驟 3 執行測試
1.建立您的解決方案,確保所有內容都是最新的。
2.開啟 Visual Studio 中的 Test Explorer (Test > Test Explorer)。
3.按一下 Test Explorer 中的"Run All"按鈕來執行單元測試。
4.檢閱測試結果。 你應該看到你寫的測試(WithdrawAmount_ValidTransaction_ReturnsTrue)通過了。

透過這種方式,我們可以隔離想要測試的程式碼,並透過有效的模擬依賴關係,確保程式碼在各種情況下的行為符合預期。 這種做法可提高軟體的可靠性和可維護性,讓您更容易在開發過程中及早發現並修復問題。
介紹 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");
}
}
Imports IronPdf
Friend Class Program
Shared Sub Main(ByVal args() As String)
Dim renderer = New ChromePdfRenderer()
' 1. Convert HTML String to PDF
Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")
' 2. Convert HTML File to PDF
Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")
' 3. Convert URL to PDF
Dim url = "http://ironpdf.com" ' Specify the URL
Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
pdfFromUrl.SaveAs("URLToPDF.pdf")
End Sub
End Class
例如,如果您有涉及 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>";
}
}
Public Class PDFGenerator
Public Sub GenerateFinancialReport(ByVal reportData As String)
Dim renderer = New ChromePdfRenderer()
' Generate the report HTML
Dim reportHtml As String = GenerateReportHtml(reportData)
Dim pdfDocument As PdfDocument = renderer.RenderHtmlAsPdf(reportHtml)
' Save the PDF to a file or memory stream
pdfDocument.SaveAs("FinancialReport.pdf")
End Sub
Private Function GenerateReportHtml(ByVal reportData As String) As String
' 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>"
End Function
End Class
使用模擬 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());
}
}
Imports IronPdf
Imports NUnit.Framework
Friend Class PDFGeneratorTests
<Test>
Public Sub GenerateFinancialReport_CreatesCorrectPDF()
' Arrange
Dim pdfGenerator As New PDFGenerator()
Dim expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf") ' Load a mock PDF
' Act
pdfGenerator.GenerateFinancialReport("Sample report data")
Dim actualPdf = PdfDocument.FromFile("FinancialReport.pdf")
' Assert
Assert.AreEqual(actualPdf.ExtractAllText(), expectedPdf.ExtractAllText())
End Sub
End Class
在本測試程式碼中,我們產生一個模擬 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 相關的功能的質量。
Moq 在測試 C# 中的依賴交互中起什麼作用?
Moq 幫助測試依賴交互,允許開發人員創建接口的模擬實現,例如 `IHostBank` 和 `IHSMModule`。這允許您模擬各種場景並驗證代碼如預期地與依賴交互。
Moq 如何處理嚴格驗證和寬鬆驗證?
Moq 支持嚴格驗證和寬鬆驗證。嚴格驗證要求滿足所有期望,對於精確測試非常有用。寬鬆驗證則更靈活,允許只驗證感興趣的交互,在複雜系統中很有幫助。



