C#中级:单元测试与Mock框架(NUnit、Moq)
·
C#中级:单元测试与Mock框架(NUnit与Moq)
一、单元测试核心概念
-
目的:
- 验证代码单元(如方法、类)的独立功能
- 确保修改不破坏现有逻辑(回归测试)
- 提升代码可维护性与设计质量
-
FIRST原则:
- Fast(快速):测试应在毫秒级完成
- Isolated(隔离):不依赖外部资源(数据库/网络)
- Repeatable(可重复):任何环境结果一致
- Self-validating(自验证):自动判断通过/失败
- Timely(及时):测试与开发同步进行
二、NUnit框架基础
.NET主流测试框架,通过NuGet安装:
Install-Package NUnit3TestAdapter
Install-Package NUnit
核心特性:
[TestFixture] // 测试类标记
public class CalculatorTests
{
private Calculator _calc;
[SetUp] // 每个测试前执行
public void Setup() => _calc = new Calculator();
[TearDown] // 每个测试后执行
public void Cleanup() => _calc = null;
[Test] // 测试方法
public void Add_TwoNumbers_ReturnsSum()
{
// Arrange
int a = 5, b = 3;
// Act
int result = _calc.Add(a, b);
// Assert
Assert.That(result, Is.EqualTo(8)); // 结果断言
}
[TestCase(1, 2, 3)] // 参数化测试
[TestCase(-1, 1, 0)]
public void Add_MultipleCases_Valid(int x, int y, int expected)
{
Assert.That(_calc.Add(x, y), Is.EqualTo(expected));
}
}
三、Moq框架详解
模拟框架(通过NuGet安装):
Install-Package Moq
核心功能:
public interface IOrderService
{
bool PlaceOrder(string item, int quantity);
}
// 测试中使用Moq
[Test]
public void ProcessOrder_ValidItem_CallsService()
{
// 1. 创建Mock对象
var mockService = new Mock<IOrderService>();
// 2. 设置模拟行为
mockService.Setup(m =>
m.PlaceOrder(It.IsAny<string>(), It.IsInRange(1, 10, Range.Inclusive))
).Returns(true); // 当参数满足条件时返回true
var processor = new OrderProcessor(mockService.Object);
// 3. 执行测试
bool result = processor.ProcessOrder("Laptop", 3);
// 4. 验证交互
Assert.IsTrue(result);
mockService.Verify(m =>
m.PlaceOrder("Laptop", 3), Times.Once); // 验证方法调用次数
}
四、综合应用示例
场景:测试支付服务,模拟支付网关依赖
// 依赖接口
public interface IPaymentGateway
{
bool ProcessPayment(decimal amount);
}
// 被测类
public class PaymentService
{
private readonly IPaymentGateway _gateway;
public PaymentService(IPaymentGateway gateway) => _gateway = gateway;
public string MakePayment(decimal amount) =>
_gateway.ProcessPayment(amount) ? "Success" : "Failed";
}
// 单元测试
[TestFixture]
public class PaymentServiceTests
{
[Test]
public void MakePayment_ValidAmount_ReturnsSuccess()
{
// 创建Mock网关
var mockGateway = new Mock<IPaymentGateway>();
mockGateway.Setup(g => g.ProcessPayment(100)).Returns(true);
// 注入Mock对象
var service = new PaymentService(mockGateway.Object);
// 执行并验证
var result = service.MakePayment(100);
Assert.That(result, Is.EqualTo("Success"));
mockGateway.Verify(g => g.ProcessPayment(100), Times.Once);
}
}
五、最佳实践
-
测试命名规范:
[被测方法]_[测试条件]_[预期结果]
(例:MakePayment_InvalidAmount_ThrowsException) -
Mock使用原则:
- 仅模拟外部依赖(数据库/API/文件系统)
- 避免过度模拟,保持测试真实性
- 优先测试正常路径,再覆盖边界情况
-
测试覆盖率:
使用工具(如Coverlet)监控覆盖率,建议核心模块覆盖率达$80%$以上:dotnet test --collect:"XPlat Code Coverage"
关键提示:结合
NUnit的[TestCase]与Moq的It.Is<T>()可高效构建参数化模拟测试,大幅减少重复代码。
更多推荐
所有评论(0)