使用 MOQ 的 TDD






3.17/5 (8投票s)
使用 Mocking Framework 的测试驱动开发
引言
在本文中,我将解释如何使用 mocking framework 进行测试驱动开发。当前文章中的示例将使用 MOQ (mocking framework) 进行开发。我使用 Visual Studio 2013 IDE 进行开发。
背景
现在许多开发都专注于测试驱动开发。测试驱动开发确实增加了开发成本,但它也使我们免受代码缺陷的困扰。每次开发代码时,都要针对它编写一个单元测试。这将保护您的代码免受任何无效代码或错误的影响,这些代码或错误可能会在新模块开发或错误修复过程中注入。每次进行代码更改时,请确保针对它执行测试。
编写具有 100% 代码覆盖率的单元测试也同样重要。我们稍后将讨论代码覆盖率。
使用代码
在我们开始编码之前,让我们使用 NuGet 添加对 MOQ 的引用。这将在我们的项目中设置所需的引用 DLL。
假设我们有一个类,如果客户已处于活动模式,则需要停用该客户。我们已经在业务层中实现了此逻辑。在测试时,我们不希望访问我们的数据库。我们的数据库访问层是接口驱动的实现,&接口看起来像这样
public interface ICustomer
{
bool IsActive { get; set; }
bool DeActivate();
}
业务层代码将如下所示。业务层将数据访问层作为输入参数放入其构造函数中。通过将数据层作为参数注入,我们不会将代码与数据层紧密结合。这还将帮助我们注入模拟对象以进行测试。
public class BLCustomer
{
protected ICustomer _Customer = null;
public BLCustomer(ICustomer customer)
{
_Customer = customer;
}
public void DeActivateCustomer()
{
if (_Customer.IsActive)
{
_Customer.DeActivate();
}
}
}
在我们开始实现之前,请注意,使用 MOQ,您只能模拟接口、抽象类 & 已标记为 virtual 的公共方法。
使用列表将命名空间 MOQ 添加到您的命名空间。 使用 Moq.Mock 类创建模拟数据访问实例
Mock<ICustomer> mockCustomerDl = new Mock<ICustomer>();
现在我们需要设置我们的实例,以便在验证 IsActive 属性时返回 true。我们可以这样做到。
mockCustomerDl.SetupGet(prop => prop.IsActive).Returns(true);
这里我们使用 SetupGet 方法来模拟 ICustomer 属性 IsActive。这将让 Mock 实例知道,当我们从 IsActive 属性访问 get 时,它应该始终返回 true。我们使用 Lambda 表达式来访问 ICustomer 接口中的属性列表。类似地,要模拟 DeActivate 方法,我们将必须使用 Moq.Mock.Setup. 以下是设置 DeActivate 方法的代码。
mockCustomerDl.Setup(meth => meth.DeActivate()).Returns(true);
现在唯一待处理的项目是将模拟对象注入 Customer 业务层。要访问 mock,我们需要使用 mock 实例的 Object 属性
BLCustomer blCustomer = new BLCustomer(mockCustomerDl.Object);
现在我们的代码已准备好使用 Mock framework 进行测试。完整的代码将如下所示
Mock<ICustomer> mockCustomerDl = new Mock<ICustomer>();
mockCustomerDl.SetupGet(prop => prop.IsActive).Returns(true);
mockCustomerDl.Setup(meth => meth.DeActivate()).Returns(true);
BLCustomer blCustomer = new BLCustomer(mockCustomerDl.Object);
blCustomer.DeActivateCustomer();
现在,当我们执行我们的代码时,它不会调用实际的数据访问层,但此请求将被路由到 Mock 对象。
MOQ 中还有一些更有趣的 Mock 功能。我已经列出了一些供您参考。
- Mock.Verify
- Mock.SetupSet
- Moq.Times