c#单元测试:使用Moq框架Mock对象

在.net中有几种mock框架可供选择,比如NMock,PhinoMocks,FakeItEasy和Moq。尽管Moq相对较新,但是它非常易用。不需要像传统的Record/Replay。并且使用Moq在VS中可以得到智能提示。学习成本也不高。

这篇文章我们介绍下如何使用Moq来mock吧。

假定我们要做一个计算器提供基本的算术运算和不同货币的转换。

ICaculator接口定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CalculatorPkg
{
    public interface ICalculator
    {
        int Add(int param1, int param2);
        int Subtract(int param1, int param2);
        int Multipy(int param1, int param2);
        int Divide(int param1, int param2);
        int ConvertUSDtoRMB(int unit);
    }
}

假定人民币转美元的接口定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MoneyExchangeRatePkg
{
    public interface IUSD_RMB_ExchangeRateFeed
    {
        int GetActualUSDValue();
    }
}

下面是Calculator的实现类,其中人民币转美元的接口实例以构造函数参数的形式传给Calculator类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoneyExchangeRatePkg;

namespace CalculatorPkg
{
    public class Calculator : ICalculator
    {
        private IUSD_RMB_ExchangeRateFeed _feed;
        public Calculator(IUSD_RMB_ExchangeRateFeed feed)
        {
            this._feed = feed;
        }
        #region ICalculator Members
        public int Add(int param1, int param2)
        {
            throw new NotImplementedException();
        } 
        public int Subtract(int param1, int param2)
        {
            throw new NotImplementedException();
        }
        public int Multipy(int param1, int param2)
        {
            throw new NotImplementedException();
        }
        public int Divide(int param1, int param2)
        {
            return param1 / param2;
        }
        public int ConvertUSDtoRMB(int unit)
        {
            return unit * this._feed.GetActualUSDValue();
        }
        #endregion
    }
}

下面我们开始准备Calculator组件的测试环境,我们使用NUnit框架和Moq来做Mock。

您可以到http://www.nunit.org/获得nunit,到http://code.google.com/p/moq/获得moq框架的源码和dll文件。

然后我们就可以创建测试项目,并添加nunit和moq的引用。

我们要mock汇率的接口,下面是mock的方法:

Mock<IUSD_RMB_ExchangeRateFeed> mockObject = new Mock<IUSD_RMB_ExchangeRateFeed>();
mockObject.Setup(m => m.GetActualUSDValue()).Returns(500);
IUSD_RMB_ExchangeRateFeed value = mockObject.Object;

对汇率接口的MOCK只需要三行代码,第一行声明mock接口,第二行设定要mock方法的返回值,第三步通过Object属性获得mock的对象。

下面是完整的测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Moq;
using CalculatorPkg;
using MoneyExchangeRatePkg;

namespace CalculatorPkg.Tests
{
    // 添加TestFixture标识类是测试类
    [TestFixture]
    public class CalculatorTester
    {
        // 定义mock的逻辑
        private IUSD_RMB_ExchangeRateFeed prvGetMockExchangeRateFeed()
        {
            Mock<IUSD_RMB_ExchangeRateFeed> mockObject = new Mock<IUSD_RMB_ExchangeRateFeed>();
            mockObject.Setup(m => m.GetActualUSDValue()).Returns(500);
            return mockObject.Object;
        }
        // 测试divide方法
        [Test(Description="Divide 9 by 3. Expected result is 3.")]
        public void TC1_Divide9By3()
        {
            IUSD_RMB_ExchangeRateFeed feed = this.prvGetMockExchangeRateFeed();
            ICalculator calculator = new Calculator(feed);
            int actualResult = calculator.Divide(9,3);
            int expectedResult = 3;
            Assert.AreEqual(expectedResult, actualResult);
        }
        [Test(Description = "Divide any number by zero. Should throw an System.DivideByZeroException exception.")]
        [ExpectedException(typeof(System.DivideByZeroException))]
        public void TC2_DivideByZero()
        {
            IUSD_RMB_ExchangeRateFeed feed = this.prvGetMockExchangeRateFeed();
            ICalculator calculator = new Calculator(feed);
            int actualResult = calculator.Divide(9, 0);
        }
        [Test(Description = "Convert 1 USD to RMB. Expected result is 500.")]
        public void TC3_ConvertUSDtoRMBTest()
        {
            IUSD_RMB_ExchangeRateFeed feed = this.prvGetMockExchangeRateFeed();
            ICalculator calculator = new Calculator(feed);
            int actualResult = calculator.ConvertUSDtoRMB(1);
            int expectedResult = 500;
            Assert.AreEqual(expectedResult, actualResult);
        }
    }
}
 
posted @   遥望星空  阅读(15138)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2015-03-17 HTTP POST GET 本质区别详解
2013-03-17 在Windows Server 2012上安装SharePoint 2010 SP1
2011-03-17 阮一峰:四位计算机的原理及其实现
点击右上角即可分享
微信分享提示