65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MOQ 的 TDD

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.17/5 (8投票s)

2014年2月18日

CPOL

2分钟阅读

viewsIcon

39516

使用 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 功能。我已经列出了一些供您参考。

  1. Mock.Verify
  2. Mock.SetupSet
  3. Moq.Times  

© . All rights reserved.